@innet/server 1.0.0

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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +788 -0
  3. package/action/Action/Action.d.ts +41 -0
  4. package/action/Action/Action.es6.js +97 -0
  5. package/action/Action/Action.js +137 -0
  6. package/action/Action/index.d.ts +2 -0
  7. package/action/Action/index.es6.js +1 -0
  8. package/action/Action/index.js +11 -0
  9. package/action/index.d.ts +4 -0
  10. package/action/index.es6.js +2 -0
  11. package/action/index.js +13 -0
  12. package/action/withAction/index.d.ts +2 -0
  13. package/action/withAction/index.es6.js +1 -0
  14. package/action/withAction/index.js +7 -0
  15. package/action/withAction/withAction.d.ts +11 -0
  16. package/action/withAction/withAction.es6.js +12 -0
  17. package/action/withAction/withAction.js +18 -0
  18. package/constants.d.ts +1 -0
  19. package/constants.es6.js +3 -0
  20. package/constants.js +7 -0
  21. package/handler/handler.d.ts +38 -0
  22. package/handler/handler.es6.js +45 -0
  23. package/handler/handler.js +56 -0
  24. package/handler/index.d.ts +2 -0
  25. package/handler/index.es6.js +1 -0
  26. package/handler/index.js +12 -0
  27. package/index.d.ts +6 -0
  28. package/index.es6.js +12 -0
  29. package/index.js +41 -0
  30. package/package.json +37 -0
  31. package/plugins/cms/cms.d.ts +9 -0
  32. package/plugins/cms/cms.es6.js +25 -0
  33. package/plugins/cms/cms.js +34 -0
  34. package/plugins/cms/index.d.ts +1 -0
  35. package/plugins/cms/index.es6.js +1 -0
  36. package/plugins/cms/index.js +9 -0
  37. package/plugins/cookie/cookie.d.ts +14 -0
  38. package/plugins/cookie/cookie.es6.js +17 -0
  39. package/plugins/cookie/cookie.js +25 -0
  40. package/plugins/cookie/index.d.ts +1 -0
  41. package/plugins/cookie/index.es6.js +1 -0
  42. package/plugins/cookie/index.js +9 -0
  43. package/plugins/error/error.d.ts +61 -0
  44. package/plugins/error/error.es6.js +68 -0
  45. package/plugins/error/error.js +78 -0
  46. package/plugins/error/index.d.ts +1 -0
  47. package/plugins/error/index.es6.js +1 -0
  48. package/plugins/error/index.js +10 -0
  49. package/plugins/file/file.d.ts +7 -0
  50. package/plugins/file/file.es6.js +24 -0
  51. package/plugins/file/file.js +34 -0
  52. package/plugins/file/index.d.ts +1 -0
  53. package/plugins/file/index.es6.js +1 -0
  54. package/plugins/file/index.js +9 -0
  55. package/plugins/header/header.d.ts +12 -0
  56. package/plugins/header/header.es6.js +10 -0
  57. package/plugins/header/header.js +19 -0
  58. package/plugins/header/index.d.ts +1 -0
  59. package/plugins/header/index.es6.js +1 -0
  60. package/plugins/header/index.js +9 -0
  61. package/plugins/index.d.ts +8 -0
  62. package/plugins/index.es6.js +8 -0
  63. package/plugins/index.js +28 -0
  64. package/plugins/proxy/index.d.ts +1 -0
  65. package/plugins/proxy/index.es6.js +1 -0
  66. package/plugins/proxy/index.js +9 -0
  67. package/plugins/proxy/proxy.d.ts +10 -0
  68. package/plugins/proxy/proxy.es6.js +13 -0
  69. package/plugins/proxy/proxy.js +22 -0
  70. package/plugins/router/index.d.ts +1 -0
  71. package/plugins/router/index.es6.js +1 -0
  72. package/plugins/router/index.js +12 -0
  73. package/plugins/router/router.d.ts +29 -0
  74. package/plugins/router/router.es6.js +54 -0
  75. package/plugins/router/router.js +70 -0
  76. package/plugins/success/index.d.ts +1 -0
  77. package/plugins/success/index.es6.js +1 -0
  78. package/plugins/success/index.js +10 -0
  79. package/plugins/success/success.d.ts +19 -0
  80. package/plugins/success/success.es6.js +30 -0
  81. package/plugins/success/success.js +40 -0
  82. package/server/index.d.ts +2 -0
  83. package/server/index.es6.js +1 -0
  84. package/server/index.js +10 -0
  85. package/server/server.d.ts +19 -0
  86. package/server/server.es6.js +63 -0
  87. package/server/server.js +92 -0
package/README.md ADDED
@@ -0,0 +1,788 @@
1
+
2
+ <a href="https://www.npmjs.com/package/innet">
3
+ <img src="https://raw.githubusercontent.com/d8corp/innet/main/logo.svg" align="left" width="90" height="90" alt="InnetJs logo by Mikhail Lysikov">
4
+ </a>
5
+
6
+ # &nbsp; @innet/server
7
+
8
+ &nbsp;
9
+
10
+ [![NPM](https://img.shields.io/npm/v/@innet/server.svg)](https://www.npmjs.com/package/@innet/server)
11
+ [![downloads](https://img.shields.io/npm/dm/@innet/server.svg)](https://www.npmtrends.com/@innet/server)
12
+ [![changelog](https://img.shields.io/badge/Changelog-⋮-brightgreen)](https://changelogs.xyz/@innet/server)
13
+ [![license](https://img.shields.io/npm/l/@innet/server)](https://github.com/d8corp/innet-server/blob/main/LICENSE)
14
+
15
+ ## Abstract
16
+ This package helps to create server-side application.
17
+
18
+ Here you find **JSX components on back-end side** 🎉, cms, routing, proxy, html rendering and more.
19
+
20
+ Based on [innet](https://www.npmjs.com/package/innet).
21
+
22
+ [![stars](https://img.shields.io/github/stars/d8corp/innet-server?style=social)](https://github.com/d8corp/innet-server/stargazers)
23
+ [![watchers](https://img.shields.io/github/watchers/d8corp/innet-server?style=social)](https://github.com/d8corp/innet-server/watchers)
24
+
25
+ ## Install
26
+ The simplest way is using `innetjs`
27
+
28
+ ```shell
29
+ npx innetjs init my-app -t be
30
+ ```
31
+ *change my-app to work folder name*
32
+
33
+ Go into `my-app` and check `README.md`
34
+
35
+ ## Handler
36
+
37
+ Use `server` handler to start an application.
38
+ ```typescript
39
+ import innet from 'innet'
40
+ import server from '@innet/server'
41
+
42
+ import app from './app'
43
+
44
+ innet(app, server)
45
+ ```
46
+
47
+ ## Server
48
+ To start http(s) server, use `server` element.
49
+
50
+ Try it out in `app.tsx`
51
+ ```typescript jsx
52
+ export default (
53
+ <server>
54
+ Hello World!
55
+ </server>
56
+ )
57
+ ```
58
+
59
+ Any content inside the server will be turned back to user.
60
+ In this case the user will get `Hello World` on any request.
61
+
62
+ Use `npm start` to run this server.
63
+
64
+ ### Port
65
+ To change the port of the web server you can use `port` prop.
66
+
67
+ ```typescript jsx
68
+ export default (
69
+ <server port={80}>
70
+ Hello World!
71
+ </server>
72
+ )
73
+ ```
74
+
75
+ or you can use `PORT` environment variable.
76
+
77
+ ### SSL
78
+ To have https connection you should provide SSL certificate.
79
+
80
+ ```typescript jsx
81
+ const ssl = {
82
+ key: 'local.key',
83
+ cert: 'local.crt'
84
+ }
85
+
86
+ export default (
87
+ <server ssl={ssl}>
88
+ Hello World!
89
+ </server>
90
+ )
91
+ ```
92
+
93
+ or you can use `SSL_CRT` and `SSL_KEY` environment variables.
94
+
95
+ ### onStart
96
+ You can show some message or do something right after the server starts.
97
+ ```typescript jsx
98
+ export default (
99
+ <server onStart={console.log}>
100
+ Hello World!
101
+ </server>
102
+ )
103
+ ```
104
+
105
+ ### onError
106
+ You can log errors or do something else, when the server get an error.
107
+
108
+ ```typescript jsx
109
+ export default (
110
+ <server onError={console.error}>
111
+ Hello World!
112
+ </server>
113
+ )
114
+ ```
115
+
116
+ ### onRequest
117
+ You can log any request with `onRequest` prop.
118
+
119
+ ```typescript jsx
120
+ export default (
121
+ <server onRequest={console.log}>
122
+ Hello World!
123
+ </server>
124
+ )
125
+ ```
126
+
127
+ ## HTML
128
+ You can use `html` element to return html content.
129
+
130
+ ```typescript jsx
131
+ export default (
132
+ <server>
133
+ <html>
134
+ <head>
135
+ <title>Innet App</title>
136
+ </head>
137
+ <body>
138
+ Hello World!
139
+ </body>
140
+ </html>
141
+ </server>
142
+ )
143
+ ```
144
+
145
+ You can use variables to split it anyhow.
146
+
147
+ ```typescript jsx
148
+ const content = (
149
+ <html>
150
+ <head>
151
+ <title>Innet App</title>
152
+ </head>
153
+ <body>
154
+ Hello World!
155
+ </body>
156
+ </html>
157
+ )
158
+
159
+ export default (
160
+ <server>
161
+ {content}
162
+ </server>
163
+ )
164
+ ```
165
+
166
+ ## Header
167
+ You can add an HTTP header into response with `header` element.
168
+
169
+ ```typescript jsx
170
+ const content = (
171
+ <html.../>
172
+ ) // check prev example
173
+
174
+ export default (
175
+ <server>
176
+ <header name='content-type' value='text/html'>
177
+ {content}
178
+ </header>
179
+ </server>
180
+ )
181
+ ```
182
+
183
+ Also, you can put header around the content, it works the same.
184
+
185
+ ```typescript jsx
186
+ const content = (
187
+ <html.../>
188
+ ) // check prev example
189
+
190
+ export default (
191
+ <server>
192
+ <header name='content-type' value='text/html' />
193
+ {content}
194
+ </server>
195
+ )
196
+ ```
197
+
198
+ ## File
199
+ You can return a file as a response.
200
+
201
+ ```typescript jsx
202
+ export default (
203
+ <server>
204
+ <header name='content-type' value='text/html'>
205
+ <file path='index.html' />
206
+ </header>
207
+ </server>
208
+ )
209
+ ```
210
+
211
+ In this case `content-type` will be equal to `text/html` even if the file does not exist.
212
+
213
+ You can put content into the file to apply it only if the file does exist.
214
+
215
+ ```typescript jsx
216
+ export default (
217
+ <server>
218
+ <file path='index.html'>
219
+ <header name='content-type' value='text/html' />
220
+ </file>
221
+ </server>
222
+ )
223
+ ```
224
+
225
+ Put `index.html` in the root of the project (`my-app` folder).
226
+
227
+ ## Router
228
+ The router helps to handle requests by route.
229
+ ```typescript jsx
230
+ export default (
231
+ <server>
232
+ <router>
233
+ <file path='index.html' />
234
+ </router>
235
+ </server>
236
+ )
237
+ ```
238
+
239
+ The router does nothing and returns self content.
240
+ It starts work only with the next props.
241
+
242
+ ### method
243
+ This property says that the content of the route should be run if the request method equals to the prop.
244
+
245
+ ```typescript jsx
246
+ export default (
247
+ <server>
248
+ <router method='GET'>
249
+ <file path='index.html' />
250
+ </router>
251
+ </server>
252
+ )
253
+ ```
254
+
255
+ ### path
256
+ You can set `path` to match with it.
257
+
258
+ ```typescript jsx
259
+ export default (
260
+ <server>
261
+ <router method='GET' path='/'>
262
+ <file path='index.html' />
263
+ </router>
264
+ </server>
265
+ )
266
+ ```
267
+
268
+ You will get the `index.html` only on the root path with `GET` method.
269
+
270
+ This prop has regex like syntax, so you can set the path as you wish.
271
+
272
+ ```typescript jsx
273
+ export default (
274
+ <server>
275
+ <router path='/user/[0-9]+'>
276
+ <file path='index.html' />
277
+ </router>
278
+ </server>
279
+ )
280
+ ```
281
+
282
+ To provide named params from url, use named capturing groups of regex.
283
+
284
+ ```typescript jsx
285
+ export default (
286
+ <server>
287
+ <router path='/user/(?<id>[\w-]+)'>
288
+ <file path='index.html' />
289
+ </router>
290
+ </server>
291
+ )
292
+ ```
293
+
294
+ ### ish
295
+ You can react on any path which starts with provided one.
296
+
297
+ ```typescript jsx
298
+ export default (
299
+ <server>
300
+ <router path='/test' ish>
301
+ <file path='index.html' />
302
+ </router>
303
+ </server>
304
+ )
305
+ ```
306
+
307
+ `/`, `/something`, `/test1` do not match.
308
+ `/test`, `/test/something` matches.
309
+
310
+ ### prefix
311
+
312
+ You can use a router inside another one and `prefix` helps reduce path prop.
313
+
314
+ ```typescript jsx
315
+ export default (
316
+ <server>
317
+ <router path='/test' prefix='/test' ish>
318
+ <router path='/'>
319
+ <file path='index.html' />
320
+ </router>
321
+ <router path='/404'>
322
+ <file path='404.html' />
323
+ </router>
324
+ </router>
325
+ </server>
326
+ )
327
+ ```
328
+
329
+ Here you can get `index.html` on `/test` and `404.html` on `/test/404`.
330
+
331
+ ### onMatch
332
+
333
+ You can log the requests of any router.
334
+
335
+ ```typescript jsx
336
+ export default (
337
+ <server>
338
+ <router path='/test' onMatch={console.log}>
339
+ <file path='index.html' />
340
+ </router>
341
+ </server>
342
+ )
343
+ ```
344
+
345
+ ## switch
346
+
347
+ By default,
348
+ routers in the same router runs one by one
349
+ independent to result of the previous route.
350
+
351
+ To avoid this you can use switch element.
352
+ ```typescript jsx
353
+ export default (
354
+ <server>
355
+ <switch>
356
+ <router path='/'>
357
+ <file path='index.html' />
358
+ </router>
359
+ <file path='404.html' />
360
+ </switch>
361
+ </server>
362
+ )
363
+ ```
364
+
365
+ You will get `index.html` only on the root path,
366
+ any other path will return `404.html`.
367
+
368
+ ## cms
369
+
370
+ CMS helps to return files from a folder by path.
371
+
372
+ ```typescript jsx
373
+ export default (
374
+ <server>
375
+ <switch>
376
+ <cms dir='cms' />
377
+ <file path='404.html' />
378
+ </switch>
379
+ </server>
380
+ )
381
+ ```
382
+
383
+ It will check if the file exist in cms folder then returns the file else returns `404.html`.
384
+
385
+ You can add prefix with router to handle specific path.
386
+
387
+ ```typescript jsx
388
+ export default (
389
+ <server>
390
+ <switch>
391
+ <router path='/cms' ish>
392
+ <cms dir='cms' prefix='/cms' />
393
+ </router>
394
+ <file path='404.html' />
395
+ </switch>
396
+ </server>
397
+ )
398
+ ```
399
+
400
+ ## proxy
401
+ You can proxy request.
402
+
403
+ ```typescript jsx
404
+ export default (
405
+ <server>
406
+ <switch>
407
+ <cms dir='cms' />
408
+ <proxy to='https://site.com' />
409
+ </switch>
410
+ </server>
411
+ )
412
+ ```
413
+
414
+ In this case, if you have a file in cms folder then the file will return
415
+ else makes request to the `site.com`.
416
+
417
+ ## Templates
418
+
419
+ Any template is just a function which returns content that should be run.
420
+
421
+ `server.tsx`
422
+ ```typescript jsx
423
+ export const Server = ({ cmsPrefix }) => (
424
+ <server>
425
+ <switch>
426
+ <router path={cmsPrefix} ish>
427
+ <cms dir='cms' prefix={cmsPrefix} />
428
+ </router>
429
+ <file path='404.html' />
430
+ </switch>
431
+ </server>
432
+ )
433
+ ```
434
+
435
+ and then you can use it inside `app.tsx`.
436
+
437
+ ```typescript jsx
438
+ import { Server } from './server'
439
+
440
+ export default <Server cmsPrefix='/cms' />
441
+ ```
442
+
443
+ You can use it with any other functionality, for example with `html`.
444
+
445
+ ```typescript jsx
446
+ const Html = ({ title }, children) => (
447
+ <header name='content-type' value='text/html'>
448
+ <html>
449
+ <head>
450
+ <title>{title}</title>
451
+ </head>
452
+ <body>
453
+ {children}
454
+ </body>
455
+ </html>
456
+ </header>
457
+ )
458
+
459
+ export default (
460
+ <server>
461
+ <Html title='main'>
462
+ Hello World!
463
+ </Html>
464
+ </server>
465
+ )
466
+ ```
467
+
468
+ The first argument is props, the second is children and the last one is a handler.
469
+
470
+ You can use templates inside other templates and components.
471
+
472
+ ## Components
473
+ Component has the same functionality as template but this is a class.
474
+
475
+ ```typescript jsx
476
+ class Html {
477
+ init ({ title }, children) {
478
+ return (
479
+ <header name='content-type' value='text/html'>
480
+ <html>
481
+ <head>
482
+ <title>{title}</title>
483
+ </head>
484
+ <body>
485
+ {children}
486
+ </body>
487
+ </html>
488
+ </header>
489
+ )
490
+ }
491
+ }
492
+
493
+ export default (
494
+ <server>
495
+ <Html title='main'>
496
+ Hello World!
497
+ </Html>
498
+ </server>
499
+ )
500
+ ```
501
+
502
+ constructor of the class gets the same arguments as init method and the same as a template.
503
+
504
+ ## success
505
+ If you work on REST API, you can use `success` or `error` as an answer
506
+
507
+ ```typescript jsx
508
+ export default (
509
+ <server>
510
+ <success />
511
+ </server>
512
+ )
513
+ ```
514
+
515
+ You will get `204` status (`noContent`), without content.
516
+
517
+ You can provide some data to the user by children.
518
+ ```typescript jsx
519
+ const data = {
520
+ posts: []
521
+ }
522
+
523
+ export default (
524
+ <server>
525
+ <success>
526
+ {data}
527
+ </success>
528
+ </server>
529
+ )
530
+ ```
531
+ You will get `200` status (`ok`), with body equals data.
532
+
533
+ ### status
534
+ You can set status by status prop.
535
+
536
+ ```typescript jsx
537
+ const data = {
538
+ id: '123'
539
+ }
540
+
541
+ export default (
542
+ <server>
543
+ <success status='created'>
544
+ {data}
545
+ </success>
546
+ </server>
547
+ )
548
+ ```
549
+
550
+ You will get `201` status (`created`), with data as a content.
551
+
552
+ You can use a number with `status` prop.
553
+
554
+ ```typescript jsx
555
+ const data = {
556
+ id: '123'
557
+ }
558
+
559
+ export default (
560
+ <server>
561
+ <success status={201}>
562
+ {data}
563
+ </success>
564
+ </server>
565
+ )
566
+ ```
567
+
568
+ ## error
569
+ You can return an error to the user.
570
+
571
+ ```typescript jsx
572
+ export default (
573
+ <server>
574
+ <error />
575
+ </server>
576
+ )
577
+ ```
578
+
579
+ You will get `520` status (`unknownError`).
580
+
581
+ You can provide some data to the user by children.
582
+
583
+ ```typescript jsx
584
+ const data = {
585
+ message: 'Some error!'
586
+ }
587
+
588
+ export default (
589
+ <server>
590
+ <error>
591
+ {data}
592
+ </error>
593
+ </server>
594
+ )
595
+ ```
596
+
597
+ ### status
598
+ You can change response status by `status` prop.
599
+
600
+ ```typescript jsx
601
+ const data = {
602
+ message: 'User not found!'
603
+ }
604
+
605
+ export default (
606
+ <server>
607
+ <error status='notFound'>
608
+ {data}
609
+ </error>
610
+ </server>
611
+ )
612
+ ```
613
+ Also, you can use a number with the status prop.
614
+
615
+ ```typescript jsx
616
+ const data = {
617
+ message: 'User not found!'
618
+ }
619
+
620
+ export default (
621
+ <server>
622
+ <error status={404}>
623
+ {data}
624
+ </error>
625
+ </server>
626
+ )
627
+ ```
628
+
629
+ ## cookie
630
+ You can set cookie by `cookie` element.
631
+
632
+ ```typescript jsx
633
+ const Login = ({ token }) => (
634
+ <cookie key='token' value={token}>
635
+ <success />
636
+ </cookie>
637
+ )
638
+
639
+ export default (
640
+ <server>
641
+ <Login token='test' />
642
+ </server>
643
+ )
644
+ ```
645
+
646
+ To remove cookie just provide key without value.
647
+
648
+ ```typescript jsx
649
+ export default (
650
+ <server>
651
+ <cookie key='token'>
652
+ <success />
653
+ </cookie>
654
+ </server>
655
+ )
656
+ ```
657
+
658
+ ## ACTION
659
+ Action is an object which contains `request` and `response`.
660
+ Also, it contains a couple of fields and methods.
661
+
662
+ Action available in templates and components.
663
+
664
+ ```typescript jsx
665
+ import { ACTION } from '@innet/server'
666
+
667
+ const Test = (props, child, handler) => {
668
+ const action = handler[ACTION]
669
+ const { req, res } = action
670
+
671
+ console.log(req, res)
672
+ }
673
+ ```
674
+
675
+ ### cookies
676
+ You can get cookies as an object from an action.
677
+
678
+ ```typescript jsx
679
+ import { ACTION } from '@innet/server'
680
+
681
+ const Cookies = (props, child, handler) => {
682
+ const { cookies } = handler[ACTION]
683
+
684
+ return <success>{cookies}</success>
685
+ }
686
+ ```
687
+
688
+ ### setCookie
689
+ You can set cookie with action.
690
+
691
+ ```typescript jsx
692
+ import { ACTION } from '@innet/server'
693
+
694
+ const Login = (props, child, handler) => {
695
+ const action = handler[ACTION]
696
+
697
+ action.setCookie('user', 'token')
698
+ }
699
+ ```
700
+
701
+ ### path
702
+ You can get current path with action.
703
+
704
+ ```typescript jsx
705
+ import { ACTION } from '@innet/server'
706
+
707
+ const Path = (props, child, handler) => {
708
+ const { path } = handler[ACTION]
709
+
710
+ return path
711
+ }
712
+ ```
713
+
714
+ ### search
715
+ You can get current search as an object.
716
+
717
+ ```typescript jsx
718
+ import { ACTION } from '@innet/server'
719
+
720
+ const Search = (props, child, handler) => {
721
+ const { search } = handler[ACTION]
722
+
723
+ return <success>{search}</success>
724
+ }
725
+ ```
726
+
727
+ ### body
728
+ You can parse body, and get values.
729
+
730
+ ```typescript jsx
731
+ import { ACTION } from '@innet/server'
732
+
733
+ const Body = async (props, child, handler) => {
734
+ const action = handler[ACTION]
735
+
736
+ await action.parseBody()
737
+
738
+ return <success>{action.body}</success>
739
+ }
740
+ ```
741
+
742
+ ### files
743
+ You can get files from a user.
744
+
745
+ ```typescript jsx
746
+ import { ACTION } from '@innet/server'
747
+
748
+ const Body = async (props, child, handler) => {
749
+ const action = handler[ACTION]
750
+
751
+ await action.parseBody()
752
+
753
+ return <success>{action.files}</success>
754
+ }
755
+ ```
756
+
757
+ ## ROUTER
758
+
759
+ You can get router data in a template or component
760
+
761
+ ```typescript jsx
762
+ import { ROUTER } from '@innet/server'
763
+
764
+ const Router = async (props, child, handler) => {
765
+ const { prefix, params } = handler[ROUTER]
766
+
767
+ return <success>{{ prefix, params }}</success>
768
+ }
769
+ ```
770
+
771
+ Use named capturing groups of regex in a route path prop to add the `params`.
772
+
773
+ ```typescript jsx
774
+ export default (
775
+ <server>
776
+ <router path='/user/(?<id>[\w-]+)'>
777
+ <Router />
778
+ </router>
779
+ </server>
780
+ )
781
+ ```
782
+
783
+ In this case, you will get `id` equals `test` in the params on `/user/test` path.
784
+
785
+ ## Issues
786
+ If you find a bug or have a suggestion, please file an issue on [GitHub](https://github.com/d8corp/innet-server/issues).
787
+
788
+ [![issues](https://img.shields.io/github/issues-raw/d8corp/innet-server)](https://github.com/d8corp/innet-server/issues)