@faasjs/http 0.0.2-beta.3 → 0.0.2-beta.302

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
-
7
- var deepMerge = _interopDefault(require('@faasjs/deep_merge'));
8
- var Logger = _interopDefault(require('@faasjs/logger'));
5
+ var func = require('@faasjs/func');
6
+ var deep_merge = require('@faasjs/deep_merge');
7
+ var logger = require('@faasjs/logger');
9
8
  var crypto = require('crypto');
9
+ var zlib = require('zlib');
10
10
 
11
11
  class Session {
12
12
  constructor(cookie, config) {
@@ -36,9 +36,8 @@ class Session {
36
36
  this.changed = false;
37
37
  }
38
38
  encode(text) {
39
- if (typeof text !== 'string') {
39
+ if (typeof text !== 'string')
40
40
  text = JSON.stringify(text);
41
- }
42
41
  const iv = crypto.randomBytes(16);
43
42
  const cipher = crypto.createCipheriv(this.config.cipherName, this.secret, iv);
44
43
  const encrypted = Buffer.concat([cipher.update(text), cipher.final()]).toString('base64');
@@ -54,9 +53,8 @@ class Session {
54
53
  const hmac = crypto.createHmac(this.config.digest, this.signedSecret);
55
54
  hmac.update(signedParts[0]);
56
55
  const digest = hmac.digest('hex');
57
- if (signedParts[1] !== digest) {
56
+ if (signedParts[1] !== digest)
58
57
  throw Error('Not valid');
59
- }
60
58
  const message = Buffer.from(signedParts[0], 'base64').toString();
61
59
  const parts = message.split('--').map(function (part) {
62
60
  return Buffer.from(part, 'base64');
@@ -64,33 +62,30 @@ class Session {
64
62
  const cipher = crypto.createDecipheriv(this.config.cipherName, this.secret, parts[1]);
65
63
  const part = Buffer.from(cipher.update(parts[0])).toString('utf8');
66
64
  const final = cipher.final('utf8');
67
- const decryptor = [part, final].join('');
68
- return JSON.parse(decryptor);
65
+ const decrypt = [part, final].join('');
66
+ return JSON.parse(decrypt);
69
67
  }
70
68
  read(key) {
71
69
  return this.content[key];
72
70
  }
73
71
  write(key, value) {
74
- if (value === null || typeof value === 'undefined') {
72
+ if (value === null || typeof value === 'undefined')
75
73
  delete this.content[key];
76
- }
77
- else {
74
+ else
78
75
  this.content[key] = value;
79
- }
80
76
  this.changed = true;
81
77
  return this;
82
78
  }
83
79
  update() {
84
- if (this.changed) {
80
+ if (this.changed)
85
81
  this.cookie.write(this.config.key, this.encode(JSON.stringify(this.content)));
86
- }
87
82
  return this;
88
83
  }
89
84
  }
90
85
 
91
86
  class Cookie {
92
87
  constructor(config) {
93
- this.config = deepMerge({
88
+ this.config = deep_merge.deepMerge({
94
89
  path: '/',
95
90
  expires: 31536000,
96
91
  secure: true,
@@ -104,15 +99,13 @@ class Cookie {
104
99
  invoke(cookie) {
105
100
  this.content = Object.create(null);
106
101
  // 解析 cookie
107
- if (cookie) {
108
- cookie.split(';').map((x) => {
102
+ if (cookie)
103
+ cookie.split(';').forEach(x => {
109
104
  x = x.trim();
110
- const k = x.match(/([^=]+)/);
111
- if (k !== null) {
105
+ const k = /([^=]+)/.exec(x);
106
+ if (k !== null)
112
107
  this.content[k[0]] = decodeURIComponent(x.replace(`${k[0]}=`, '').replace(/;$/, ''));
113
- }
114
108
  });
115
- }
116
109
  this.setCookie = Object.create(null);
117
110
  // 预读取 session
118
111
  this.session.invoke(this.read(this.session.config.key));
@@ -133,78 +126,60 @@ class Cookie {
133
126
  cookie = `${key}=${encodeURIComponent(value)};`;
134
127
  this.content[key] = value;
135
128
  }
136
- if (typeof opts.expires === 'number') {
129
+ if (typeof opts.expires === 'number')
137
130
  cookie += `max-age=${opts.expires};`;
138
- }
139
- else if (typeof opts.expires === 'string') {
131
+ else if (typeof opts.expires === 'string')
140
132
  cookie += `expires=${opts.expires};`;
141
- }
142
133
  cookie += `path=${opts.path || '/'};`;
143
- if (opts.domain) {
134
+ if (opts.domain)
144
135
  cookie += `domain=${opts.domain};`;
145
- }
146
- if (opts.secure) {
136
+ if (opts.secure)
147
137
  cookie += 'Secure;';
148
- }
149
- if (opts.httpOnly) {
138
+ if (opts.httpOnly)
150
139
  cookie += 'HttpOnly;';
151
- }
152
- if (opts.sameSite) {
140
+ if (opts.sameSite)
153
141
  cookie += `SameSite=${opts.sameSite};`;
154
- }
155
142
  this.setCookie[key] = cookie;
156
143
  return this;
157
144
  }
158
145
  headers() {
159
- if (!Object.keys(this.setCookie).length) {
146
+ if (Object.keys(this.setCookie).length === 0)
160
147
  return {};
161
- }
162
- else {
163
- return {
164
- 'Set-Cookie': Object.values(this.setCookie)
165
- };
166
- }
148
+ else
149
+ return { 'Set-Cookie': Object.values(this.setCookie) };
167
150
  }
168
151
  }
169
152
 
170
- class ValidError extends Error {
171
- constructor({ statusCode, headers, message }) {
172
- super(message);
173
- this.statusCode = statusCode || 500;
174
- this.headers = headers || Object.create(null);
175
- }
176
- }
177
153
  class Validator {
178
- constructor(config) {
154
+ constructor(config, logger) {
179
155
  this.paramsConfig = config.params;
180
156
  this.cookieConfig = config.cookie;
181
157
  this.sessionConfig = config.session;
182
- this.logger = new Logger('Http.Validator');
158
+ this.before = config.before;
159
+ this.logger = logger;
183
160
  }
184
- valid({ params, cookie, session }) {
185
- this.request = {
186
- params,
187
- cookie,
188
- session
189
- };
190
- this.logger.debug('Begin');
191
- if (this.paramsConfig) {
192
- this.logger.debug('Valid params');
193
- this.validContent('params', params, '', this.paramsConfig);
194
- }
195
- if (this.cookieConfig) {
196
- this.logger.debug('Valid cookie');
197
- if (!cookie) {
161
+ async valid(request) {
162
+ if (this.before) {
163
+ const result = await this.before(request);
164
+ if (result)
165
+ throw new HttpError(result);
166
+ }
167
+ this.request = request;
168
+ if (this.paramsConfig && request.params) {
169
+ this.logger.debug('Valid Params');
170
+ this.validContent('params', request.params, '', this.paramsConfig);
171
+ }
172
+ if (this.cookieConfig && request.cookie) {
173
+ this.logger.debug('Valid Cookie');
174
+ if (request.cookie == null)
198
175
  throw Error('Not found Cookie');
199
- }
200
- this.validContent('cookie', cookie.content, '', this.cookieConfig);
176
+ this.validContent('cookie', request.cookie.content, '', this.cookieConfig);
201
177
  }
202
- if (this.sessionConfig) {
178
+ if (this.sessionConfig && request.session) {
203
179
  this.logger.debug('Valid Session');
204
- if (!session) {
180
+ if (request.session == null)
205
181
  throw Error('Not found Session');
206
- }
207
- this.validContent('session', session.content, '', this.sessionConfig);
182
+ this.validContent('session', request.session.content, '', this.sessionConfig);
208
183
  }
209
184
  }
210
185
  validContent(type, params, baseKey, config) {
@@ -212,57 +187,50 @@ class Validator {
212
187
  const paramsKeys = Object.keys(params);
213
188
  const rulesKeys = Object.keys(config.rules);
214
189
  const diff = paramsKeys.filter(k => !rulesKeys.includes(k));
215
- if (diff.length) {
190
+ if (diff.length > 0)
216
191
  if (config.whitelist === 'error') {
217
192
  const diffKeys = diff.map(k => `${baseKey}${k}`);
218
- const error = Error(`[${type}] Unpermitted keys: ${diffKeys.join(', ')}`);
193
+ const error = Error(`[${type}] Not permitted keys: ${diffKeys.join(', ')}`);
219
194
  if (config.onError) {
220
195
  const res = config.onError(`${type}.whitelist`, baseKey, diffKeys);
221
- if (res) {
222
- throw new ValidError(res);
223
- }
196
+ if (res)
197
+ throw new HttpError(res);
224
198
  }
225
199
  throw error;
226
200
  }
227
- else if (config.whitelist === 'ignore') {
228
- for (const key of diff) {
201
+ else if (config.whitelist === 'ignore')
202
+ for (const key of diff)
229
203
  delete params[key];
230
- }
231
- }
232
- }
233
204
  }
234
205
  for (const key in config.rules) {
235
206
  const rule = config.rules[key];
207
+ if (!rule)
208
+ continue;
236
209
  let value = params[key];
237
210
  // default
238
- if (rule.default) {
239
- if (type === 'cookie' || type === 'session') {
211
+ if (rule.default)
212
+ if (type === 'cookie' || type === 'session')
240
213
  this.logger.warn('Cookie and Session not support default rule.');
241
- }
242
214
  else if (typeof value === 'undefined' && rule.default) {
243
215
  value = typeof rule.default === 'function' ? rule.default(this.request) : rule.default;
244
216
  params[key] = value;
245
217
  }
246
- }
247
218
  // required
248
- if (rule.required === true) {
219
+ if (rule.required)
249
220
  if (typeof value === 'undefined' || value === null) {
250
221
  const error = Error(`[${type}] ${baseKey}${key} is required.`);
251
222
  if (config.onError) {
252
223
  const res = config.onError(`${type}.rule.required`, `${baseKey}${key}`, value);
253
- if (res) {
254
- throw new ValidError(res);
255
- }
224
+ if (res)
225
+ throw new HttpError(res);
256
226
  }
257
227
  throw error;
258
228
  }
259
- }
260
229
  if (typeof value !== 'undefined' && value !== null) {
261
230
  // type
262
- if (rule.type) {
263
- if (type === 'cookie') {
231
+ if (rule.type)
232
+ if (type === 'cookie')
264
233
  this.logger.warn('Cookie not support type rule');
265
- }
266
234
  else {
267
235
  let typed = true;
268
236
  switch (rule.type) {
@@ -280,43 +248,33 @@ class Validator {
280
248
  const error = Error(`[${type}] ${baseKey}${key} must be a ${rule.type}.`);
281
249
  if (config.onError) {
282
250
  const res = config.onError(`${type}.rule.type`, `${baseKey}${key}`, value);
283
- if (res) {
284
- throw new ValidError(res);
285
- }
251
+ if (res)
252
+ throw new HttpError(res);
286
253
  }
287
254
  throw error;
288
255
  }
289
256
  }
290
- }
291
257
  // in
292
- if (rule.in && !rule.in.includes(value)) {
258
+ if ((rule.in) && !rule.in.includes(value)) {
293
259
  const error = Error(`[${type}] ${baseKey}${key} must be in ${rule.in.join(', ')}.`);
294
260
  if (config.onError) {
295
261
  const res = config.onError(`${type}.rule.in`, `${baseKey}${key}`, value);
296
- if (res) {
297
- throw new ValidError(res);
298
- }
262
+ if (res)
263
+ throw new HttpError(res);
299
264
  }
300
265
  throw error;
301
266
  }
302
267
  // nest config
303
- if (rule.config) {
304
- if (type === 'cookie') {
268
+ if (rule.config)
269
+ if (type === 'cookie')
305
270
  this.logger.warn('Cookie not support nest rule.');
306
- }
307
- else {
308
- if (Array.isArray(value)) {
309
- // array
310
- for (const val of value) {
311
- this.validContent(type, val, (baseKey ? `${baseKey}.${key}.` : `${key}.`), rule.config);
312
- }
313
- }
314
- else if (typeof value === 'object') {
315
- // object
316
- this.validContent(type, value, (baseKey ? `${baseKey}.${key}.` : `${key}.`), rule.config);
317
- }
318
- }
319
- }
271
+ else if (Array.isArray(value))
272
+ // array
273
+ for (const val of value)
274
+ this.validContent(type, val, (baseKey ? `${baseKey}.${key}.` : `${key}.`), rule.config);
275
+ else if (typeof value === 'object')
276
+ // object
277
+ this.validContent(type, value, (baseKey ? `${baseKey}.${key}.` : `${key}.`), rule.config);
320
278
  }
321
279
  }
322
280
  }
@@ -332,12 +290,26 @@ const ContentType = {
332
290
  json: 'application/json',
333
291
  jsonp: 'application/javascript'
334
292
  };
293
+ class HttpError extends Error {
294
+ constructor({ statusCode, message }) {
295
+ super(message);
296
+ if (Error.captureStackTrace)
297
+ Error.captureStackTrace(this, HttpError);
298
+ this.statusCode = statusCode || 500;
299
+ this.message = message;
300
+ }
301
+ }
302
+ const Name = 'http';
335
303
  class Http {
336
304
  /**
337
305
  * 创建 Http 插件实例
338
306
  * @param config {object} 配置项
339
307
  * @param config.name {string} 配置名
340
308
  * @param config.config {object} 网关配置
309
+ * @param config.config.method {string} 请求方法,默认为 POST
310
+ * @param config.config.path {string} 请求路径,默认为云函数文件路径
311
+ * @param config.config.ignorePathPrefix {string} 排除的路径前缀,当设置 path 时无效
312
+ * @param config.config.cookie {object} Cookie 配置
341
313
  * @param config.validator {object} 入参校验配置
342
314
  * @param config.validator.params {object} params 校验配置
343
315
  * @param config.validator.params.whitelist {string} 白名单配置
@@ -351,56 +323,66 @@ class Http {
351
323
  * @param config.validator.session.whitelist {string} 白名单配置
352
324
  * @param config.validator.session.onError {function} 自定义报错
353
325
  * @param config.validator.session.rules {object} 参数校验规则
326
+ * @param config.validator.before {function} 参数校验前自定义函数
354
327
  */
355
- constructor(config = Object.create(null)) {
356
- this.logger = new Logger('Http');
357
- this.type = 'http';
358
- this.name = config.name;
359
- this.config = config.config || Object.create(null);
360
- if (config.validator) {
328
+ constructor(config) {
329
+ this.type = Name;
330
+ this.name = Name;
331
+ this.name = (config === null || config === void 0 ? void 0 : config.name) || this.type;
332
+ this.config = ((config === null || config === void 0 ? void 0 : config.config)) || Object.create(null);
333
+ if ((config === null || config === void 0 ? void 0 : config.validator))
361
334
  this.validatorOptions = config.validator;
362
- }
335
+ this.logger = new logger.Logger(this.name);
363
336
  this.headers = Object.create(null);
364
337
  this.cookie = new Cookie(this.config.cookie || {});
365
338
  this.session = this.cookie.session;
366
339
  }
367
340
  async onDeploy(data, next) {
341
+ var _a;
368
342
  await next();
369
- this.logger.debug('[Http] 组装网关配置');
370
- this.logger.debug('%o', data);
371
- const config = deepMerge(data.config.plugins[this.name || this.type], { config: this.config });
343
+ this.logger.debug('组装网关配置');
344
+ this.logger.debug('%j', data);
345
+ const config = data.config.plugins ?
346
+ deep_merge.deepMerge(data.config.plugins[this.name || this.type], { config: this.config }) :
347
+ { config: this.config };
372
348
  // 根据文件及文件夹名生成路径
373
- config.config.path = '=/' + data.name.replace(/_/g, '/').replace(/\/index$/, '');
374
- this.logger.debug('[Http] 组装完成 %o', config);
349
+ if (!config.config.path) {
350
+ config.config.path = '/' + ((_a = data.name) === null || _a === void 0 ? void 0 : _a.replace(/_/g, '/').replace(/\/index$/, ''));
351
+ if (config.config.path === '/index')
352
+ config.config.path = '/';
353
+ if (config.config.ignorePathPrefix) {
354
+ config.config.path = config.config.path.replace(new RegExp('^' + config.config.ignorePathPrefix), '');
355
+ if (config.config.path === '')
356
+ config.config.path = '/';
357
+ }
358
+ }
359
+ this.logger.debug('组装完成 %j', config);
375
360
  // 引用服务商部署插件
376
- // eslint-disable-next-line security/detect-non-literal-require, @typescript-eslint/no-var-requires
377
- const Provider = require(config.provider.type);
361
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
362
+ const Provider = require(config.provider.type).Provider;
378
363
  const provider = new Provider(config.provider.config);
379
364
  // 部署网关
380
365
  await provider.deploy(this.type, data, config);
381
366
  }
382
367
  async onMount(data, next) {
383
368
  this.logger.debug('[onMount] merge config');
384
- if (data.config.plugins[this.name || this.type]) {
385
- this.config = deepMerge(this.config, data.config.plugins[this.name || this.type].config);
386
- }
369
+ if (data.config.plugins && data.config.plugins[this.name || this.type])
370
+ this.config = deep_merge.deepMerge(this.config, data.config.plugins[this.name || this.type].config);
387
371
  this.logger.debug('[onMount] prepare cookie & session');
388
372
  this.cookie = new Cookie(this.config.cookie || {});
389
373
  this.session = this.cookie.session;
390
374
  if (this.validatorOptions) {
391
375
  this.logger.debug('[onMount] prepare validator');
392
- this.validator = new Validator(this.validatorOptions);
376
+ this.validator = new Validator(this.validatorOptions, this.logger);
393
377
  }
394
378
  await next();
395
379
  }
396
380
  async onInvoke(data, next) {
397
- this.logger.debug('[onInvoke] Parse & valid');
398
- this.logger.time('http');
381
+ var _a, _b;
399
382
  this.headers = data.event.headers || Object.create(null);
383
+ this.body = data.event.body;
400
384
  this.params = Object.create(null);
401
- this.response = {
402
- headers: Object.create(null)
403
- };
385
+ this.response = { headers: Object.create(null) };
404
386
  if (data.event.body) {
405
387
  if (data.event.headers && data.event.headers['content-type'] && data.event.headers['content-type'].includes('application/json')) {
406
388
  this.logger.debug('[onInvoke] Parse params from json body');
@@ -410,19 +392,23 @@ class Http {
410
392
  this.logger.debug('[onInvoke] Parse params from raw body');
411
393
  this.params = data.event.body;
412
394
  }
395
+ this.logger.debug('[onInvoke] Params: %j', this.params);
413
396
  }
414
397
  else if (data.event.queryString) {
415
398
  this.logger.debug('[onInvoke] Parse params from queryString');
416
399
  this.params = data.event.queryString;
400
+ this.logger.debug('[onInvoke] Params: %j', this.params);
401
+ }
402
+ this.cookie.invoke(this.headers.cookie);
403
+ if (this.headers.cookie) {
404
+ this.logger.debug('[onInvoke] Cookie: %j', this.cookie.content);
405
+ this.logger.debug('[onInvoke] Session: %j', this.session.content);
417
406
  }
418
- this.logger.debug('[onInvoke] Parse cookie');
419
- this.cookie.invoke(this.headers['cookie']);
420
- this.logger.debug('[onInvoke] Cookie: %o', this.cookie.content);
421
- this.logger.debug('[onInvoke] Session: %o', this.session.content);
422
407
  if (this.validator) {
423
408
  this.logger.debug('[onInvoke] Valid request');
424
409
  try {
425
- this.validator.valid({
410
+ await this.validator.valid({
411
+ headers: this.headers,
426
412
  params: this.params,
427
413
  cookie: this.cookie,
428
414
  session: this.session
@@ -432,53 +418,85 @@ class Http {
432
418
  this.logger.error(error);
433
419
  data.response = {
434
420
  statusCode: error.statusCode || 500,
435
- headers: Object.assign({
436
- 'Content-Type': 'application/json; charset=utf-8',
437
- 'X-Request-Id': data.context.request_id
438
- }, error.headers || {}),
439
- body: JSON.stringify({
440
- error: {
441
- message: error.message
442
- }
443
- })
421
+ headers: { 'Content-Type': 'application/json; charset=utf-8' },
422
+ body: JSON.stringify({ error: { message: error.message } })
444
423
  };
445
424
  return;
446
425
  }
447
426
  }
448
- this.logger.timeEnd('http', '[onInvoke] Parse & valid done');
449
- await next();
450
- this.logger.debug('[onInvoke] Generate response');
451
- this.logger.time('http');
452
- // update seesion
427
+ try {
428
+ await next();
429
+ }
430
+ catch (error) {
431
+ data.response = error;
432
+ }
433
+ // update session
453
434
  this.session.update();
454
435
  // 处理 body
455
- if (data.response) {
456
- if (data.response instanceof Error || (data.response.constructor && data.response.constructor.name === 'Error')) {
436
+ if (data.response)
437
+ if (data.response instanceof Error || ((_a = data.response.constructor) === null || _a === void 0 ? void 0 : _a.name) === 'Error') {
457
438
  // 当结果是错误类型时
458
439
  this.logger.error(data.response);
459
440
  this.response.body = JSON.stringify({ error: { message: data.response.message } });
460
- this.response.statusCode = 500;
441
+ try {
442
+ this.response.statusCode = data.response.statusCode || 500;
443
+ }
444
+ catch (error) {
445
+ this.response.statusCode = 500;
446
+ }
461
447
  }
462
- else if (Object.prototype.toString.call(data.response) === '[object Object]' && data.response.statusCode && data.response.headers) {
448
+ else if (Object.prototype.toString.call(data.response) === '[object Object]' && data.response.statusCode && data.response.headers)
463
449
  // 当返回结果是响应结构体时
464
450
  this.response = data.response;
465
- }
466
- else {
451
+ else
467
452
  this.response.body = JSON.stringify({ data: data.response });
468
- }
469
- }
470
453
  // 处理 statusCode
471
- if (!this.response.statusCode) {
454
+ if (!this.response.statusCode)
472
455
  this.response.statusCode = this.response.body ? 200 : 201;
473
- }
474
456
  // 处理 headers
475
457
  this.response.headers = Object.assign({
476
458
  'Content-Type': 'application/json; charset=utf-8',
477
- 'X-Request-Id': new Date().getTime().toString()
459
+ 'Cache-Control': 'no-cache, no-store'
478
460
  }, this.cookie.headers(), this.response.headers);
479
- /* eslint-disable-next-line require-atomic-updates */
480
461
  data.response = this.response;
481
- this.logger.timeEnd('http', '[onInvoke] done');
462
+ if (process.env.FaasMode === 'local') {
463
+ this.logger.debug('[onInvoke] Response: %j', data.response);
464
+ return;
465
+ }
466
+ // 判断是否需要压缩
467
+ if (data.response.isBase64Encoded ||
468
+ typeof data.response.body !== 'string' ||
469
+ !((_b = data.response.headers['Content-Type']) === null || _b === void 0 ? void 0 : _b.includes('json')) ||
470
+ data.response.body.length < 100)
471
+ return;
472
+ const acceptEncoding = this.headers['accept-encoding'] || this.headers['Accept-Encoding'];
473
+ if (!acceptEncoding || !/(br|gzip|deflate)/.test(acceptEncoding))
474
+ return;
475
+ const originBody = data.response.body;
476
+ try {
477
+ if (acceptEncoding.includes('br')) {
478
+ data.response.headers['Content-Encoding'] = 'br';
479
+ data.response.body = zlib.brotliCompressSync(originBody).toString('base64');
480
+ }
481
+ else if (acceptEncoding.includes('gzip')) {
482
+ data.response.headers['Content-Encoding'] = 'gzip';
483
+ data.response.body = zlib.gzipSync(originBody).toString('base64');
484
+ }
485
+ else if (acceptEncoding.includes('deflate')) {
486
+ data.response.headers['Content-Encoding'] = 'deflate';
487
+ data.response.body = zlib.deflateSync(originBody).toString('base64');
488
+ }
489
+ else
490
+ throw Error('No matched compression.');
491
+ data.response.isBase64Encoded = true;
492
+ data.response.originBody = originBody;
493
+ }
494
+ catch (error) {
495
+ console.error(error);
496
+ // 若压缩失败还原
497
+ data.response.body = originBody;
498
+ delete data.response.headers['Content-Encoding'];
499
+ }
482
500
  }
483
501
  /**
484
502
  * 设置 header
@@ -495,12 +513,10 @@ class Http {
495
513
  * @param charset {string} 编码
496
514
  */
497
515
  setContentType(type, charset = 'utf-8') {
498
- if (ContentType[type]) {
516
+ if (ContentType[type])
499
517
  this.setHeader('Content-Type', `${ContentType[type]}; charset=${charset}`);
500
- }
501
- else {
518
+ else
502
519
  this.setHeader('Content-Type', `${type}; charset=${charset}`);
503
- }
504
520
  return this;
505
521
  }
506
522
  /**
@@ -519,10 +535,15 @@ class Http {
519
535
  this.response.body = body;
520
536
  return this;
521
537
  }
538
+ }
539
+ function useHttp(config) {
540
+ return func.usePlugin(new Http(config));
522
541
  }
523
542
 
524
543
  exports.ContentType = ContentType;
525
544
  exports.Cookie = Cookie;
526
545
  exports.Http = Http;
546
+ exports.HttpError = HttpError;
527
547
  exports.Session = Session;
528
548
  exports.Validator = Validator;
549
+ exports.useHttp = useHttp;
package/lib/session.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Cookie } from './cookie';
2
- export interface SessionOptions {
2
+ export declare type SessionOptions = {
3
3
  key: string;
4
4
  secret: string;
5
5
  salt?: string;
@@ -8,11 +8,12 @@ export interface SessionOptions {
8
8
  iterations?: number;
9
9
  digest?: string;
10
10
  cipherName?: string;
11
- }
12
- export declare class Session {
13
- content: {
14
- [key: string]: any;
15
- };
11
+ };
12
+ export declare type SessionContent = string | number | {
13
+ [key: string]: any;
14
+ } | null | undefined;
15
+ export declare class Session<S extends Record<string, string> = any, C extends Record<string, string> = any> {
16
+ content: Record<string, string>;
16
17
  readonly config: {
17
18
  key: string;
18
19
  secret: string;
@@ -23,15 +24,15 @@ export declare class Session {
23
24
  digest: string;
24
25
  cipherName: string;
25
26
  };
26
- private secret;
27
- private signedSecret;
28
- private cookie;
27
+ private readonly secret;
28
+ private readonly signedSecret;
29
+ private readonly cookie;
29
30
  private changed?;
30
- constructor(cookie: Cookie, config: SessionOptions);
31
+ constructor(cookie: Cookie<C, S>, config: SessionOptions);
31
32
  invoke(cookie?: string): void;
32
- encode(text: any): string;
33
- decode(text: string): any;
34
- read(key: string): any;
35
- write(key: string, value?: any): this;
36
- update(): this;
33
+ encode(text: SessionContent): string;
34
+ decode(text: string): SessionContent;
35
+ read(key: string): string;
36
+ write(key: string, value?: string): Session<S, C>;
37
+ update(): Session<S, C>;
37
38
  }