@innet/server 2.0.0-alpha.7 → 2.0.0-alpha.9

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/README.md CHANGED
@@ -317,7 +317,9 @@ This section contains elements of utils.
317
317
 
318
318
  [\<swagger>](#swagger)
319
319
  [\<dev>](#dev)
320
+ [\<prod>](#prod)
320
321
  [\<dts>](#dts)
322
+ [\<protection>](#protection)
321
323
 
322
324
  ---
323
325
 
@@ -374,6 +376,25 @@ export default (
374
376
  )
375
377
  ```
376
378
 
379
+ ### \<prod>
380
+
381
+ [← back](#utils)
382
+
383
+ Everything inside <prod> will work when `NODE_ENV` equals `production`.
384
+
385
+ *src/app.tsx*
386
+ ```typescript jsx
387
+ export default (
388
+ <server>
389
+ <api>
390
+ <prod>
391
+ <swagger />
392
+ </prod>
393
+ </api>
394
+ </server>
395
+ )
396
+ ```
397
+
377
398
  ### \<dts>
378
399
 
379
400
  [← back](#utils)
@@ -419,6 +440,149 @@ export function DeleteTodo () {
419
440
  }
420
441
  ```
421
442
 
443
+ ### \<protection>
444
+
445
+ [← back](#utils)
446
+
447
+ This element adds protection page.
448
+ You can use it when you want to protect your application.
449
+ This element MUST be placed in `<api>` element.
450
+
451
+ #### html
452
+
453
+ `<protection>` has a required prop of `html`.
454
+ This is a `string` of HTML a user will see if they have no protection.
455
+
456
+ *src/app.tsx*
457
+ ```typescript jsx
458
+ import html from './protection.html'
459
+
460
+ export default (
461
+ <server>
462
+ <api>
463
+ <protection
464
+ html={html}
465
+ />
466
+ </api>
467
+ </server>
468
+ )
469
+ ```
470
+
471
+ #### value
472
+
473
+ This prop is a secret string of protection value.
474
+ User must provide a protection query param equals the `value`.
475
+
476
+ By default, the value is `undefined` and protection does not work.
477
+ You can use `PROTECTION` env to set default protection `value`.
478
+
479
+ *src/app.tsx*
480
+ ```typescript jsx
481
+ import html from './protection.html'
482
+
483
+ export default (
484
+ <server>
485
+ <api>
486
+ <protection
487
+ value='secret'
488
+ html={html}
489
+ />
490
+ </api>
491
+ </server>
492
+ )
493
+ ```
494
+
495
+ #### maxAge
496
+
497
+ This prop sets how much time protection is qualified.
498
+
499
+ By default, the prop equals a year.
500
+ You can use `PROTECTION_MAX_AGE` env to set default `maxAge`.
501
+
502
+ *src/app.tsx*
503
+ ```typescript jsx
504
+ import html from './protection.html'
505
+
506
+ export default (
507
+ <server>
508
+ <api>
509
+ <protection
510
+ maxAge={24 * 60 * 60}
511
+ html={html}
512
+ />
513
+ </api>
514
+ </server>
515
+ )
516
+ ```
517
+
518
+ #### excludeIp
519
+
520
+ This prop sets a list of IP addresses (split by `,`) to ignore the protection.
521
+
522
+ You can use `PROTECTED_IP` env to set default `excludeIp`.
523
+
524
+ *src/app.tsx*
525
+ ```typescript jsx
526
+ import html from './protection.html'
527
+
528
+ export default (
529
+ <server>
530
+ <api>
531
+ <protection
532
+ excludeIp='0.0.0.0,127.0.0.0'
533
+ html={html}
534
+ />
535
+ </api>
536
+ </server>
537
+ )
538
+ ```
539
+
540
+ #### cookieKey
541
+
542
+ This prop sets a cookie field name used to store protection of a user.
543
+
544
+ By default, it equals `protection`.
545
+ You can use `PROTECTION_COOKIE_KEY` env to set default `cookieKey`.
546
+
547
+ *src/app.tsx*
548
+ ```typescript jsx
549
+ import html from './protection.html'
550
+
551
+ export default (
552
+ <server>
553
+ <api>
554
+ <protection
555
+ cookieKey='secret'
556
+ html={html}
557
+ />
558
+ </api>
559
+ </server>
560
+ )
561
+ ```
562
+
563
+ #### searchKey
564
+
565
+ This prop sets a search query field name used to check protection.
566
+
567
+ By default, it equals `protection`.
568
+ You can use `PROTECTION_SEARCH_KEY` env to set default `searchKey`.
569
+
570
+ *src/app.tsx*
571
+ ```typescript jsx
572
+ import html from './protection.html'
573
+
574
+ export default (
575
+ <server>
576
+ <api>
577
+ <protection
578
+ searchKey='secret'
579
+ html={html}
580
+ />
581
+ </api>
582
+ </server>
583
+ )
584
+ ```
585
+
422
586
  ## API Info
423
587
 
424
588
  The API information elements are here.
@@ -3317,7 +3481,7 @@ Hook functions give you all features to control parent element functionality.
3317
3481
 
3318
3482
  [← back](#index)
3319
3483
 
3320
- [useServer](#useserver)
3484
+ Real-time
3321
3485
  [useRequest](#userequest)
3322
3486
  [useResponse](#useresponse)
3323
3487
  [useHeaders](#useheaders)
@@ -3326,31 +3490,16 @@ Hook functions give you all features to control parent element functionality.
3326
3490
  [useParams](#useparams)
3327
3491
  [useSearch](#usesearch)
3328
3492
  [useBody](#usebody)
3329
- [useComponentName](#usecomponentname)
3330
- [useRequestPlugin](#userequestplugin)
3493
+ [useClientIp](#useclientip)
3331
3494
 
3332
- ---
3495
+ Server start
3496
+ [useRequestPlugin](#userequestplugin)
3333
3497
 
3334
- ### useServer
3335
-
3336
- [← back](#hooks)
3337
-
3338
- This hook MUST be used in a component placed in `<server>`.
3339
- This hook returns current http(s) server instance.
3340
-
3341
- *src/Component.tsx*
3342
-
3343
- ```typescript jsx
3344
- import { useServer } from '@innet/sever'
3345
-
3346
- export function Component () {
3347
- const server = useServer()
3348
-
3349
- console.log(server)
3498
+ Both
3499
+ [useServer](#useserver)
3500
+ [useComponentName](#usecomponentname)
3350
3501
 
3351
- return <success />
3352
- }
3353
- ```
3502
+ ---
3354
3503
 
3355
3504
  ### useRequest
3356
3505
 
@@ -3505,21 +3654,21 @@ export function Component () {
3505
3654
  }
3506
3655
  ```
3507
3656
 
3508
- ### useComponentName
3657
+ ### useClientIp
3509
3658
 
3510
3659
  [← back](#hooks)
3511
3660
 
3512
- This hook returns name of current component.
3661
+ This hook returns request user IP.
3662
+ This hook MUST be used in a component placed in [\<request>](#request) or [\<fallback>](#fallback).
3513
3663
 
3514
3664
  *src/Component.tsx*
3515
3665
  ```typescript jsx
3516
- import { useComponentName } from '@innet/sever'
3666
+ import { useClientIp } from '@innet/sever'
3517
3667
 
3518
3668
  export function Component () {
3519
- // returns this ^-------^
3520
- const name = useComponentName()
3521
-
3522
- return <success>{{ name }}</success>
3669
+ const ip = useClientIp()
3670
+
3671
+ return <success>{{ ip }}</success>
3523
3672
  }
3524
3673
  ```
3525
3674
 
@@ -3531,6 +3680,8 @@ This hook adds a request plugin function.
3531
3680
  The function runs before check endpoints.
3532
3681
  If the function returns `true` the request handling stops, and you get full control over the request.
3533
3682
 
3683
+ This hook MUST be used in a component placed in [\<api>](#api).
3684
+
3534
3685
  *src/SecretEndpoint.tsx*
3535
3686
  ```typescript jsx
3536
3687
  import { useRequestPlugin } from '@innet/sever'
@@ -3568,6 +3719,44 @@ export default (
3568
3719
  Any endpoint returns an error except for `/secret-endpoint`.
3569
3720
  Elements order does not matter.
3570
3721
 
3722
+ ### useServer
3723
+
3724
+ [← back](#hooks)
3725
+
3726
+ This hook MUST be used in a component placed in [\<server>](#server).
3727
+ This hook returns current http(s) server instance.
3728
+
3729
+ *src/Component.tsx*
3730
+ ```typescript jsx
3731
+ import { useServer } from '@innet/sever'
3732
+
3733
+ export function Component () {
3734
+ const server = useServer()
3735
+
3736
+ console.log(server)
3737
+
3738
+ return <success />
3739
+ }
3740
+ ```
3741
+
3742
+ ### useComponentName
3743
+
3744
+ [← back](#hooks)
3745
+
3746
+ This hook returns name of current component.
3747
+
3748
+ *src/Component.tsx*
3749
+ ```typescript jsx
3750
+ import { useComponentName } from '@innet/sever'
3751
+
3752
+ export function Component () {
3753
+ // returns this ^-------^
3754
+ const name = useComponentName()
3755
+
3756
+ return <success>{{ name }}</success>
3757
+ }
3758
+ ```
3759
+
3571
3760
  ## Issues
3572
3761
  If you find a bug or have a suggestion, please file an issue on [GitHub](https://github.com/d8corp/innet-server/issues).
3573
3762
 
@@ -1,6 +1,6 @@
1
1
  import { context, type ContextProps, slot, type SlotProps, slots, type SlotsProps } from '@innet/jsx';
2
2
  import { arraySync, async } from '@innet/utils';
3
- import { type ApiProps, type ArrayProps, type BinaryProps, type BodyProps, type BooleanProps, cms, type CmsProps, type ContactProps, type CookieProps, type DateProps, type DevProps, type DtsProps, type EndpointProps, type ErrorProps, type FallbackProps, type FieldProps, file, type FileProps, type HeaderProps, type HostProps, type IntegerProps, type LicenseProps, type NullProps, type NumberProps, type ObjectProps, type ParamProps, type ProdProps, type ProxyProps, type RedirectProps, type RequestProps, type ResponseProps, type ServerProps, type StringProps, type SuccessProps, type SwaggerProps, type TagProps, type TupleProps, type UuidProps, type VariableProps } from '../plugins';
3
+ import { type ApiProps, type ArrayProps, type BinaryProps, type BodyProps, type BooleanProps, cms, type CmsProps, type ContactProps, type CookieProps, type DateProps, type DevProps, type DtsProps, type EndpointProps, type ErrorProps, type FallbackProps, type FieldProps, file, type FileProps, type HeaderProps, type HostProps, type IntegerProps, type LicenseProps, type NullProps, type NumberProps, type ObjectProps, type ParamProps, type ProdProps, protection, type ProtectionProps, type ProxyProps, type RedirectProps, type RequestProps, type ResponseProps, type ServerProps, type StringProps, type SuccessProps, type SwaggerProps, type TagProps, type TupleProps, type UuidProps, type VariableProps } from '../plugins';
4
4
  export declare const arrayPlugins: (typeof arraySync)[];
5
5
  export declare const JSXPlugins: {
6
6
  api: import("innet").HandlerPlugin;
@@ -29,6 +29,7 @@ export declare const JSXPlugins: {
29
29
  object: import("innet").HandlerPlugin;
30
30
  param: import("innet").HandlerPlugin;
31
31
  prod: import("innet").HandlerPlugin;
32
+ protection: typeof protection;
32
33
  proxy: import("innet").HandlerPlugin;
33
34
  redirect: import("innet").HandlerPlugin;
34
35
  request: import("innet").HandlerPlugin;
@@ -77,6 +78,7 @@ declare global {
77
78
  object: ObjectProps;
78
79
  param: ParamProps;
79
80
  prod: ProdProps;
81
+ protection: ProtectionProps;
80
82
  proxy: ProxyProps;
81
83
  redirect: RedirectProps;
82
84
  request: RequestProps;
@@ -27,6 +27,7 @@ import { number } from '../plugins/schema/number/number.es6.js';
27
27
  import { object } from '../plugins/schema/object/object.es6.js';
28
28
  import { param } from '../plugins/main/param/param.es6.js';
29
29
  import { prod } from '../plugins/utils/prod/prod.es6.js';
30
+ import { protection } from '../plugins/utils/protection/protection.es6.js';
30
31
  import { proxy } from '../plugins/request/proxy/proxy.es6.js';
31
32
  import { redirect } from '../plugins/request/redirect/redirect.es6.js';
32
33
  import { request } from '../plugins/main/request/request.es6.js';
@@ -71,6 +72,7 @@ const JSXPlugins = {
71
72
  object,
72
73
  param,
73
74
  prod,
75
+ protection,
74
76
  proxy,
75
77
  redirect,
76
78
  request,
@@ -31,6 +31,7 @@ var number = require('../plugins/schema/number/number.js');
31
31
  var object = require('../plugins/schema/object/object.js');
32
32
  var param = require('../plugins/main/param/param.js');
33
33
  var prod = require('../plugins/utils/prod/prod.js');
34
+ var protection = require('../plugins/utils/protection/protection.js');
34
35
  var proxy = require('../plugins/request/proxy/proxy.js');
35
36
  var redirect = require('../plugins/request/redirect/redirect.js');
36
37
  var request = require('../plugins/main/request/request.js');
@@ -75,6 +76,7 @@ const JSXPlugins = {
75
76
  object: object.object,
76
77
  param: param.param,
77
78
  prod: prod.prod,
79
+ protection: protection.protection,
78
80
  proxy: proxy.proxy,
79
81
  redirect: redirect.redirect,
80
82
  request: request.request,
package/hooks/index.d.ts CHANGED
@@ -24,3 +24,4 @@ export * from './useObjectRule';
24
24
  export * from './useBodyFile';
25
25
  export * from './usePath';
26
26
  export * from './useRequestPlugin';
27
+ export * from './useClientIp';
@@ -24,3 +24,4 @@ import './useObjectRule/index.es6.js';
24
24
  import './useBodyFile/index.es6.js';
25
25
  import './usePath/index.es6.js';
26
26
  import './useRequestPlugin/index.es6.js';
27
+ import './useClientIp/index.es6.js';
package/hooks/index.js CHANGED
@@ -26,4 +26,5 @@ require('./useObjectRule/index.js');
26
26
  require('./useBodyFile/index.js');
27
27
  require('./usePath/index.js');
28
28
  require('./useRequestPlugin/index.js');
29
+ require('./useClientIp/index.js');
29
30
 
@@ -0,0 +1 @@
1
+ export * from './useClientIp';
@@ -0,0 +1 @@
1
+ export { useClientIp } from './useClientIp.es6.js';
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var useClientIp = require('./useClientIp.js');
6
+
7
+
8
+
9
+ exports.useClientIp = useClientIp.useClientIp;
@@ -0,0 +1 @@
1
+ export declare function useClientIp(): string | null;
@@ -0,0 +1,9 @@
1
+ import '../useAction/index.es6.js';
2
+ import { useAction } from '../useAction/useAction.es6.js';
3
+
4
+ function useClientIp() {
5
+ const action = useAction();
6
+ return action.clientIp;
7
+ }
8
+
9
+ export { useClientIp };
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ require('../useAction/index.js');
6
+ var useAction = require('../useAction/useAction.js');
7
+
8
+ function useClientIp() {
9
+ const action = useAction.useAction();
10
+ return action.clientIp;
11
+ }
12
+
13
+ exports.useClientIp = useClientIp;
package/index.es6.js CHANGED
@@ -41,6 +41,7 @@ export { swagger } from './plugins/utils/swagger/swagger.es6.js';
41
41
  export { dts } from './plugins/utils/dts/dts.es6.js';
42
42
  export { dev } from './plugins/utils/dev/dev.es6.js';
43
43
  export { prod } from './plugins/utils/prod/prod.es6.js';
44
+ export { protection } from './plugins/utils/protection/protection.es6.js';
44
45
  export { serverFn } from './plugins/handler/serverFn/serverFn.es6.js';
45
46
  export { EMPTY_SEARCH, parseSearch } from './utils/parseSearch/parseSearch.es6.js';
46
47
  export { stringifySearch } from './utils/stringifySearch/stringifySearch.es6.js';
@@ -108,3 +109,4 @@ export { objectRuleContext, useObjectRule } from './hooks/useObjectRule/useObjec
108
109
  export { bodyFileContext, useBodyFile } from './hooks/useBodyFile/useBodyFile.es6.js';
109
110
  export { usePath } from './hooks/usePath/usePath.es6.js';
110
111
  export { useRequestPlugin } from './hooks/useRequestPlugin/useRequestPlugin.es6.js';
112
+ export { useClientIp } from './hooks/useClientIp/useClientIp.es6.js';
package/index.js CHANGED
@@ -45,6 +45,7 @@ var swagger = require('./plugins/utils/swagger/swagger.js');
45
45
  var dts = require('./plugins/utils/dts/dts.js');
46
46
  var dev = require('./plugins/utils/dev/dev.js');
47
47
  var prod = require('./plugins/utils/prod/prod.js');
48
+ var protection = require('./plugins/utils/protection/protection.js');
48
49
  var serverFn = require('./plugins/handler/serverFn/serverFn.js');
49
50
  var parseSearch = require('./utils/parseSearch/parseSearch.js');
50
51
  var stringifySearch = require('./utils/stringifySearch/stringifySearch.js');
@@ -112,6 +113,7 @@ var useObjectRule = require('./hooks/useObjectRule/useObjectRule.js');
112
113
  var useBodyFile = require('./hooks/useBodyFile/useBodyFile.js');
113
114
  var usePath = require('./hooks/usePath/usePath.js');
114
115
  var useRequestPlugin = require('./hooks/useRequestPlugin/useRequestPlugin.js');
116
+ var useClientIp = require('./hooks/useClientIp/useClientIp.js');
115
117
 
116
118
 
117
119
 
@@ -162,6 +164,7 @@ exports.swagger = swagger.swagger;
162
164
  exports.dts = dts.dts;
163
165
  exports.dev = dev.dev;
164
166
  exports.prod = prod.prod;
167
+ exports.protection = protection.protection;
165
168
  exports.serverFn = serverFn.serverFn;
166
169
  exports.EMPTY_SEARCH = parseSearch.EMPTY_SEARCH;
167
170
  exports.parseSearch = parseSearch.parseSearch;
@@ -248,3 +251,4 @@ exports.bodyFileContext = useBodyFile.bodyFileContext;
248
251
  exports.useBodyFile = useBodyFile.useBodyFile;
249
252
  exports.usePath = usePath.usePath;
250
253
  exports.useRequestPlugin = useRequestPlugin.useRequestPlugin;
254
+ exports.useClientIp = useClientIp.useClientIp;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@innet/server",
3
- "version": "2.0.0-alpha.7",
3
+ "version": "2.0.0-alpha.9",
4
4
  "description": "Create server-side application with innet",
5
5
  "main": "index.js",
6
6
  "module": "index.es6.js",
@@ -49,6 +49,7 @@
49
49
  "multiparty": "^4.2.3",
50
50
  "openapi-types": "^12.1.3",
51
51
  "qs": "^6.11.2",
52
+ "request-ip": "^3.3.0",
52
53
  "string_decoder": "^1.3.0",
53
54
  "tslib": "^2.6.1",
54
55
  "uuid": "^9.0.0",
@@ -34,7 +34,7 @@ const api = () => {
34
34
  var _b, _c, _d, _e, _f, _g;
35
35
  if (res.writableEnded)
36
36
  return;
37
- const action = new Action(req);
37
+ const action = new Action(req, res);
38
38
  const path = action.parsedUrl.path;
39
39
  const url = path.endsWith('/') ? path.slice(0, -1) : path;
40
40
  if (url === (prefix || '')) {
@@ -47,7 +47,7 @@ const api = () => {
47
47
  return;
48
48
  }
49
49
  for (const requestPlugin of requestPlugins) {
50
- if (requestPlugin(req, res))
50
+ if (requestPlugin(action))
51
51
  return;
52
52
  }
53
53
  const method = ((_c = (_b = req.method) === null || _b === void 0 ? void 0 : _b.toLowerCase()) !== null && _c !== void 0 ? _c : 'get');
@@ -42,7 +42,7 @@ const api = () => {
42
42
  var _b, _c, _d, _e, _f, _g;
43
43
  if (res.writableEnded)
44
44
  return;
45
- const action = new Action.Action(req);
45
+ const action = new Action.Action(req, res);
46
46
  const path = action.parsedUrl.path;
47
47
  const url = path.endsWith('/') ? path.slice(0, -1) : path;
48
48
  if (url === (prefix || '')) {
@@ -55,7 +55,7 @@ const api = () => {
55
55
  return;
56
56
  }
57
57
  for (const requestPlugin of requestPlugins) {
58
- if (requestPlugin(req, res))
58
+ if (requestPlugin(action))
59
59
  return;
60
60
  }
61
61
  const method = ((_c = (_b = req.method) === null || _b === void 0 ? void 0 : _b.toLowerCase()) !== null && _c !== void 0 ? _c : 'get');
@@ -1,28 +1,12 @@
1
1
  import { __rest } from 'tslib';
2
2
  import { useProps } from '@innet/jsx';
3
- import cookie$1 from 'cookie';
4
3
  import '../../../hooks/index.es6.js';
5
- import { useResponse } from '../../../hooks/useResponse/useResponse.es6.js';
6
- import { useThrow } from '../../../hooks/useThrow/useThrow.es6.js';
4
+ import { useAction } from '../../../hooks/useAction/useAction.es6.js';
7
5
 
8
6
  const cookie = () => {
9
- const res = useResponse();
10
- if (!res) {
11
- useThrow('<{type}> MUST be in <request> or <fallback>');
12
- }
7
+ const action = useAction();
13
8
  const _a = useProps(), { key, value } = _a, opt = __rest(_a, ["key", "value"]);
14
- let cookies = res.getHeader('Set-Cookie');
15
- if (typeof cookies === 'string') {
16
- cookies = [cookies];
17
- }
18
- const normValue = typeof value === 'string' ? cookie$1.serialize(key, value, opt) : `${key}=; max-age=0`;
19
- if (cookies) {
20
- cookies.push(normValue);
21
- }
22
- else {
23
- cookies = normValue;
24
- }
25
- res.setHeader('Set-Cookie', cookies);
9
+ action.setCookie(key, value, opt);
26
10
  };
27
11
 
28
12
  export { cookie };
@@ -4,33 +4,13 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var tslib = require('tslib');
6
6
  var jsx = require('@innet/jsx');
7
- var cookie$1 = require('cookie');
8
7
  require('../../../hooks/index.js');
9
- var useResponse = require('../../../hooks/useResponse/useResponse.js');
10
- var useThrow = require('../../../hooks/useThrow/useThrow.js');
11
-
12
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
13
-
14
- var cookie__default = /*#__PURE__*/_interopDefaultLegacy(cookie$1);
8
+ var useAction = require('../../../hooks/useAction/useAction.js');
15
9
 
16
10
  const cookie = () => {
17
- const res = useResponse.useResponse();
18
- if (!res) {
19
- useThrow.useThrow('<{type}> MUST be in <request> or <fallback>');
20
- }
11
+ const action = useAction.useAction();
21
12
  const _a = jsx.useProps(), { key, value } = _a, opt = tslib.__rest(_a, ["key", "value"]);
22
- let cookies = res.getHeader('Set-Cookie');
23
- if (typeof cookies === 'string') {
24
- cookies = [cookies];
25
- }
26
- const normValue = typeof value === 'string' ? cookie__default["default"].serialize(key, value, opt) : `${key}=; max-age=0`;
27
- if (cookies) {
28
- cookies.push(normValue);
29
- }
30
- else {
31
- cookies = normValue;
32
- }
33
- res.setHeader('Set-Cookie', cookies);
13
+ action.setCookie(key, value, opt);
34
14
  };
35
15
 
36
16
  exports.cookie = cookie;
@@ -2,3 +2,4 @@ export * from './swagger';
2
2
  export * from './dts';
3
3
  export * from './dev';
4
4
  export * from './prod';
5
+ export * from './protection';
@@ -2,3 +2,4 @@ import './swagger/index.es6.js';
2
2
  import './dts/index.es6.js';
3
3
  import './dev/index.es6.js';
4
4
  import './prod/index.es6.js';
5
+ import './protection/index.es6.js';
@@ -4,4 +4,5 @@ require('./swagger/index.js');
4
4
  require('./dts/index.js');
5
5
  require('./dev/index.js');
6
6
  require('./prod/index.js');
7
+ require('./protection/index.js');
7
8
 
@@ -0,0 +1 @@
1
+ export * from './protection';
@@ -0,0 +1 @@
1
+ export { protection } from './protection.es6.js';
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var protection = require('./protection.js');
6
+
7
+
8
+
9
+ exports.protection = protection.protection;
@@ -0,0 +1,9 @@
1
+ export interface ProtectionProps {
2
+ html: string;
3
+ value?: string;
4
+ maxAge?: number;
5
+ excludeIp?: string | string[];
6
+ cookieKey?: string;
7
+ searchKey?: string;
8
+ }
9
+ export declare function protection(): void;
@@ -0,0 +1,38 @@
1
+ import { useProps } from '@innet/jsx';
2
+ import '../../../hooks/index.es6.js';
3
+ import { useRequestPlugin } from '../../../hooks/useRequestPlugin/useRequestPlugin.es6.js';
4
+
5
+ function protection() {
6
+ const { html, maxAge = Number(process.env.PROTECTION_MAX_AGE) || 365 * 24 * 60 * 60, value = process.env.PROTECTION, excludeIp = process.env.PROTECTED_IP, cookieKey = process.env.PROTECTION_COOKIE_KEY || 'protection', searchKey = process.env.PROTECTION_SEARCH_KEY || 'protection', } = useProps();
7
+ if (!value)
8
+ return;
9
+ const excludeIps = Array.isArray(excludeIp) ? excludeIp : excludeIp === null || excludeIp === void 0 ? void 0 : excludeIp.split(',');
10
+ useRequestPlugin(action => {
11
+ if (!action.clientIp) {
12
+ action.res.write(html);
13
+ action.res.end();
14
+ return true;
15
+ }
16
+ if (excludeIps === null || excludeIps === void 0 ? void 0 : excludeIps.includes(action.clientIp))
17
+ return false;
18
+ const { [cookieKey]: cookieProtection } = action.cookies;
19
+ if (cookieProtection && cookieProtection === value)
20
+ return false;
21
+ const { [searchKey]: searchProtection } = action.search;
22
+ if (searchProtection && searchProtection === value) {
23
+ action.setCookie(cookieKey, value, {
24
+ maxAge,
25
+ httpOnly: true,
26
+ secure: true,
27
+ path: '/',
28
+ });
29
+ return false;
30
+ }
31
+ action.setCookie(cookieKey);
32
+ action.res.write(html);
33
+ action.res.end();
34
+ return true;
35
+ });
36
+ }
37
+
38
+ export { protection };
@@ -0,0 +1,42 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var jsx = require('@innet/jsx');
6
+ require('../../../hooks/index.js');
7
+ var useRequestPlugin = require('../../../hooks/useRequestPlugin/useRequestPlugin.js');
8
+
9
+ function protection() {
10
+ const { html, maxAge = Number(process.env.PROTECTION_MAX_AGE) || 365 * 24 * 60 * 60, value = process.env.PROTECTION, excludeIp = process.env.PROTECTED_IP, cookieKey = process.env.PROTECTION_COOKIE_KEY || 'protection', searchKey = process.env.PROTECTION_SEARCH_KEY || 'protection', } = jsx.useProps();
11
+ if (!value)
12
+ return;
13
+ const excludeIps = Array.isArray(excludeIp) ? excludeIp : excludeIp === null || excludeIp === void 0 ? void 0 : excludeIp.split(',');
14
+ useRequestPlugin.useRequestPlugin(action => {
15
+ if (!action.clientIp) {
16
+ action.res.write(html);
17
+ action.res.end();
18
+ return true;
19
+ }
20
+ if (excludeIps === null || excludeIps === void 0 ? void 0 : excludeIps.includes(action.clientIp))
21
+ return false;
22
+ const { [cookieKey]: cookieProtection } = action.cookies;
23
+ if (cookieProtection && cookieProtection === value)
24
+ return false;
25
+ const { [searchKey]: searchProtection } = action.search;
26
+ if (searchProtection && searchProtection === value) {
27
+ action.setCookie(cookieKey, value, {
28
+ maxAge,
29
+ httpOnly: true,
30
+ secure: true,
31
+ path: '/',
32
+ });
33
+ return false;
34
+ }
35
+ action.setCookie(cookieKey);
36
+ action.res.write(html);
37
+ action.res.end();
38
+ return true;
39
+ });
40
+ }
41
+
42
+ exports.protection = protection;
@@ -8,14 +8,14 @@ const swagger = () => {
8
8
  const { path = '/swagger-ui' } = useProps() || {};
9
9
  const { docs, prefix } = useApi();
10
10
  let swaggerResponse;
11
- useRequestPlugin((req, res) => {
12
- if (req.url === prefix + path) {
11
+ useRequestPlugin(action => {
12
+ if (action.req.url === prefix + path) {
13
13
  if (!swaggerResponse) {
14
14
  swaggerResponse = html.replace('spec: {},', `spec: ${JSON.stringify(docs)},`);
15
15
  }
16
- res.statusCode = 200;
17
- res.write(swaggerResponse);
18
- res.end();
16
+ action.res.statusCode = 200;
17
+ action.res.write(swaggerResponse);
18
+ action.res.end();
19
19
  return true;
20
20
  }
21
21
  });
@@ -12,14 +12,14 @@ const swagger = () => {
12
12
  const { path = '/swagger-ui' } = jsx.useProps() || {};
13
13
  const { docs, prefix } = useApi.useApi();
14
14
  let swaggerResponse;
15
- useRequestPlugin.useRequestPlugin((req, res) => {
16
- if (req.url === prefix + path) {
15
+ useRequestPlugin.useRequestPlugin(action => {
16
+ if (action.req.url === prefix + path) {
17
17
  if (!swaggerResponse) {
18
18
  swaggerResponse = swagger$1["default"].replace('spec: {},', `spec: ${JSON.stringify(docs)},`);
19
19
  }
20
- res.statusCode = 200;
21
- res.write(swaggerResponse);
22
- res.end();
20
+ action.res.statusCode = 200;
21
+ action.res.write(swaggerResponse);
22
+ action.res.end();
23
23
  return true;
24
24
  }
25
25
  });
package/types.d.ts CHANGED
@@ -1,8 +1,7 @@
1
- /// <reference types="node" />
2
- import type { IncomingMessage, ServerResponse } from 'http';
3
1
  import type { Handler } from 'innet';
4
2
  import type { OpenAPIV3_1 as API } from 'openapi-types';
5
3
  import type { ApiErrorValue } from './constants';
4
+ import { type Action } from './utils';
6
5
  import { type Rule, type RulesErrors } from './utils/rules';
7
6
  export type TagObject = API.TagObject;
8
7
  export type Document = API.Document;
@@ -73,4 +72,4 @@ export interface Fallback {
73
72
  children: any;
74
73
  handler: Handler;
75
74
  }
76
- export type RequestPlugin = (req: IncomingMessage, res: ServerResponse) => boolean | undefined;
75
+ export type RequestPlugin = (action: Action) => boolean | undefined;
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
- import type http from 'http';
3
- import { type IncomingHttpHeaders } from 'http';
2
+ import { type CookieSerializeOptions } from 'cookie';
3
+ import { type IncomingHttpHeaders, type IncomingMessage, type ServerResponse } from 'http';
4
4
  import { type ParsedQs } from 'qs';
5
5
  import { type BodyType } from '../../types';
6
6
  export declare const URL_PARSER: RegExp;
@@ -10,8 +10,9 @@ export interface ParsedUrl {
10
10
  }
11
11
  export declare class Action {
12
12
  #private;
13
- private readonly req;
14
- constructor(req: http.IncomingMessage);
13
+ readonly req: IncomingMessage;
14
+ readonly res: ServerResponse;
15
+ constructor(req: IncomingMessage, res: ServerResponse);
15
16
  get parsedUrl(): ParsedUrl;
16
17
  get path(): string;
17
18
  get originSearch(): ParsedQs;
@@ -26,4 +27,6 @@ export declare class Action {
26
27
  get bodyType(): BodyType | undefined;
27
28
  body?: object;
28
29
  parseBody(): Promise<void>;
30
+ setCookie(name: string, value?: string, options?: CookieSerializeOptions): void;
31
+ get clientIp(): string | null;
29
32
  }
@@ -1,5 +1,6 @@
1
1
  import { __runInitializers, __classPrivateFieldGet, __classPrivateFieldSet, __awaiter, __esDecorate } from 'tslib';
2
- import cookie from 'cookie';
2
+ import cookieLib from 'cookie';
3
+ import { getClientIp } from 'request-ip';
3
4
  import '../decorators/index.es6.js';
4
5
  import '../parseBody/index.es6.js';
5
6
  import '../parseFormBody/index.es6.js';
@@ -19,9 +20,11 @@ let Action = (() => {
19
20
  let _get_originCookies_decorators;
20
21
  let _get_bodyType_decorators;
21
22
  let _parseBody_decorators;
23
+ let _get_clientIp_decorators;
22
24
  return _a = class Action {
23
- constructor(req) {
25
+ constructor(req, res) {
24
26
  this.req = (__runInitializers(this, _instanceExtraInitializers), req);
27
+ this.res = res;
25
28
  _Action_search.set(this, void 0);
26
29
  _Action_headers.set(this, {});
27
30
  _Action_cookie.set(this, {});
@@ -66,7 +69,7 @@ let Action = (() => {
66
69
  }
67
70
  get originCookies() {
68
71
  var _a;
69
- return cookie.parse((_a = this.req.headers.cookie) !== null && _a !== void 0 ? _a : '');
72
+ return cookieLib.parse((_a = this.req.headers.cookie) !== null && _a !== void 0 ? _a : '');
70
73
  }
71
74
  get cookies() {
72
75
  if (__classPrivateFieldGet(this, _Action_cookie, "f"))
@@ -103,6 +106,23 @@ let Action = (() => {
103
106
  }
104
107
  });
105
108
  }
109
+ setCookie(name, value, options) {
110
+ let cookies = this.res.getHeader('Set-Cookie');
111
+ if (typeof cookies === 'string') {
112
+ cookies = [cookies];
113
+ }
114
+ const normValue = typeof value === 'string' ? cookieLib.serialize(name, value, options) : `${name}=; max-age=0`;
115
+ if (cookies) {
116
+ cookies.push(normValue);
117
+ }
118
+ else {
119
+ cookies = normValue;
120
+ }
121
+ this.res.setHeader('Set-Cookie', cookies);
122
+ }
123
+ get clientIp() {
124
+ return getClientIp(this.req);
125
+ }
106
126
  },
107
127
  _Action_search = new WeakMap(),
108
128
  _Action_headers = new WeakMap(),
@@ -113,11 +133,13 @@ let Action = (() => {
113
133
  _get_originCookies_decorators = [once];
114
134
  _get_bodyType_decorators = [once];
115
135
  _parseBody_decorators = [once];
136
+ _get_clientIp_decorators = [once];
116
137
  __esDecorate(_a, null, _get_parsedUrl_decorators, { kind: "getter", name: "parsedUrl", static: false, private: false, access: { has: obj => "parsedUrl" in obj, get: obj => obj.parsedUrl } }, null, _instanceExtraInitializers);
117
138
  __esDecorate(_a, null, _get_originSearch_decorators, { kind: "getter", name: "originSearch", static: false, private: false, access: { has: obj => "originSearch" in obj, get: obj => obj.originSearch } }, null, _instanceExtraInitializers);
118
139
  __esDecorate(_a, null, _get_originCookies_decorators, { kind: "getter", name: "originCookies", static: false, private: false, access: { has: obj => "originCookies" in obj, get: obj => obj.originCookies } }, null, _instanceExtraInitializers);
119
140
  __esDecorate(_a, null, _get_bodyType_decorators, { kind: "getter", name: "bodyType", static: false, private: false, access: { has: obj => "bodyType" in obj, get: obj => obj.bodyType } }, null, _instanceExtraInitializers);
120
141
  __esDecorate(_a, null, _parseBody_decorators, { kind: "method", name: "parseBody", static: false, private: false, access: { has: obj => "parseBody" in obj, get: obj => obj.parseBody } }, null, _instanceExtraInitializers);
142
+ __esDecorate(_a, null, _get_clientIp_decorators, { kind: "getter", name: "clientIp", static: false, private: false, access: { has: obj => "clientIp" in obj, get: obj => obj.clientIp } }, null, _instanceExtraInitializers);
121
143
  })(),
122
144
  _a;
123
145
  })();
@@ -3,7 +3,8 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var tslib = require('tslib');
6
- var cookie = require('cookie');
6
+ var cookieLib = require('cookie');
7
+ var requestIp = require('request-ip');
7
8
  require('../decorators/index.js');
8
9
  require('../parseBody/index.js');
9
10
  require('../parseFormBody/index.js');
@@ -16,7 +17,7 @@ var once = require('../decorators/once/once.js');
16
17
 
17
18
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
18
19
 
19
- var cookie__default = /*#__PURE__*/_interopDefaultLegacy(cookie);
20
+ var cookieLib__default = /*#__PURE__*/_interopDefaultLegacy(cookieLib);
20
21
 
21
22
  const URL_PARSER = /^(?<path>[^?]+)(\?(?<search>.*))?/;
22
23
  let Action = (() => {
@@ -27,9 +28,11 @@ let Action = (() => {
27
28
  let _get_originCookies_decorators;
28
29
  let _get_bodyType_decorators;
29
30
  let _parseBody_decorators;
31
+ let _get_clientIp_decorators;
30
32
  return _a = class Action {
31
- constructor(req) {
33
+ constructor(req, res) {
32
34
  this.req = (tslib.__runInitializers(this, _instanceExtraInitializers), req);
35
+ this.res = res;
33
36
  _Action_search.set(this, void 0);
34
37
  _Action_headers.set(this, {});
35
38
  _Action_cookie.set(this, {});
@@ -74,7 +77,7 @@ let Action = (() => {
74
77
  }
75
78
  get originCookies() {
76
79
  var _a;
77
- return cookie__default["default"].parse((_a = this.req.headers.cookie) !== null && _a !== void 0 ? _a : '');
80
+ return cookieLib__default["default"].parse((_a = this.req.headers.cookie) !== null && _a !== void 0 ? _a : '');
78
81
  }
79
82
  get cookies() {
80
83
  if (tslib.__classPrivateFieldGet(this, _Action_cookie, "f"))
@@ -111,6 +114,23 @@ let Action = (() => {
111
114
  }
112
115
  });
113
116
  }
117
+ setCookie(name, value, options) {
118
+ let cookies = this.res.getHeader('Set-Cookie');
119
+ if (typeof cookies === 'string') {
120
+ cookies = [cookies];
121
+ }
122
+ const normValue = typeof value === 'string' ? cookieLib__default["default"].serialize(name, value, options) : `${name}=; max-age=0`;
123
+ if (cookies) {
124
+ cookies.push(normValue);
125
+ }
126
+ else {
127
+ cookies = normValue;
128
+ }
129
+ this.res.setHeader('Set-Cookie', cookies);
130
+ }
131
+ get clientIp() {
132
+ return requestIp.getClientIp(this.req);
133
+ }
114
134
  },
115
135
  _Action_search = new WeakMap(),
116
136
  _Action_headers = new WeakMap(),
@@ -121,11 +141,13 @@ let Action = (() => {
121
141
  _get_originCookies_decorators = [once.once];
122
142
  _get_bodyType_decorators = [once.once];
123
143
  _parseBody_decorators = [once.once];
144
+ _get_clientIp_decorators = [once.once];
124
145
  tslib.__esDecorate(_a, null, _get_parsedUrl_decorators, { kind: "getter", name: "parsedUrl", static: false, private: false, access: { has: obj => "parsedUrl" in obj, get: obj => obj.parsedUrl } }, null, _instanceExtraInitializers);
125
146
  tslib.__esDecorate(_a, null, _get_originSearch_decorators, { kind: "getter", name: "originSearch", static: false, private: false, access: { has: obj => "originSearch" in obj, get: obj => obj.originSearch } }, null, _instanceExtraInitializers);
126
147
  tslib.__esDecorate(_a, null, _get_originCookies_decorators, { kind: "getter", name: "originCookies", static: false, private: false, access: { has: obj => "originCookies" in obj, get: obj => obj.originCookies } }, null, _instanceExtraInitializers);
127
148
  tslib.__esDecorate(_a, null, _get_bodyType_decorators, { kind: "getter", name: "bodyType", static: false, private: false, access: { has: obj => "bodyType" in obj, get: obj => obj.bodyType } }, null, _instanceExtraInitializers);
128
149
  tslib.__esDecorate(_a, null, _parseBody_decorators, { kind: "method", name: "parseBody", static: false, private: false, access: { has: obj => "parseBody" in obj, get: obj => obj.parseBody } }, null, _instanceExtraInitializers);
150
+ tslib.__esDecorate(_a, null, _get_clientIp_decorators, { kind: "getter", name: "clientIp", static: false, private: false, access: { has: obj => "clientIp" in obj, get: obj => obj.clientIp } }, null, _instanceExtraInitializers);
129
151
  })(),
130
152
  _a;
131
153
  })();