@furystack/rest-service 6.0.8 → 6.1.2

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 (79) hide show
  1. package/dist/actions/index.js +20 -7
  2. package/dist/actions/index.js.map +1 -1
  3. package/dist/api-manager.js +20 -16
  4. package/dist/api-manager.js.map +1 -1
  5. package/dist/endpoint-generators/create-delete-endpoint.spec.js +4 -2
  6. package/dist/endpoint-generators/create-delete-endpoint.spec.js.map +1 -1
  7. package/dist/endpoint-generators/create-get-collection-endpoint.js +1 -1
  8. package/dist/endpoint-generators/create-get-collection-endpoint.js.map +1 -1
  9. package/dist/endpoint-generators/create-get-collection-endpoint.spec.js +4 -2
  10. package/dist/endpoint-generators/create-get-collection-endpoint.spec.js.map +1 -1
  11. package/dist/endpoint-generators/create-get-entity-endpoint.spec.js +4 -2
  12. package/dist/endpoint-generators/create-get-entity-endpoint.spec.js.map +1 -1
  13. package/dist/endpoint-generators/create-patch-endpoint.spec.js +5 -3
  14. package/dist/endpoint-generators/create-patch-endpoint.spec.js.map +1 -1
  15. package/dist/endpoint-generators/create-post-endpoint.spec.js +5 -3
  16. package/dist/endpoint-generators/create-post-endpoint.spec.js.map +1 -1
  17. package/dist/endpoint-generators/index.js +19 -6
  18. package/dist/endpoint-generators/index.js.map +1 -1
  19. package/dist/helpers.js +15 -1
  20. package/dist/helpers.js.map +1 -1
  21. package/dist/helpers.spec.js +18 -2
  22. package/dist/helpers.spec.js.map +1 -1
  23. package/dist/http-authentication-settings.js +7 -2
  24. package/dist/http-authentication-settings.js.map +1 -1
  25. package/dist/http-user-context.js +16 -8
  26. package/dist/http-user-context.js.map +1 -1
  27. package/dist/incoming-message-extensions.js +4 -2
  28. package/dist/incoming-message-extensions.js.map +1 -1
  29. package/dist/index.js +32 -17
  30. package/dist/index.js.map +1 -1
  31. package/dist/mime-types.js +340 -0
  32. package/dist/mime-types.js.map +1 -0
  33. package/dist/mime-types.spec.js +15 -0
  34. package/dist/mime-types.spec.js.map +1 -0
  35. package/dist/models/index.js +16 -3
  36. package/dist/models/index.js.map +1 -1
  37. package/dist/rest-service.integration.spec.js +4 -2
  38. package/dist/rest-service.integration.spec.js.map +1 -1
  39. package/dist/schema-validator/index.js +16 -3
  40. package/dist/schema-validator/index.js.map +1 -1
  41. package/dist/schema-validator/schema-validator.js +5 -3
  42. package/dist/schema-validator/schema-validator.js.map +1 -1
  43. package/dist/server-manager.js +11 -3
  44. package/dist/server-manager.js.map +1 -1
  45. package/dist/server-response-extensions.js +4 -2
  46. package/dist/server-response-extensions.js.map +1 -1
  47. package/dist/static-server-manager.js +71 -0
  48. package/dist/static-server-manager.js.map +1 -0
  49. package/dist/static-server-manager.spec.js +206 -0
  50. package/dist/static-server-manager.spec.js.map +1 -0
  51. package/dist/utils.js +7 -2
  52. package/dist/utils.js.map +1 -1
  53. package/dist/validate.integration.spec.js +12 -14
  54. package/dist/validate.integration.spec.js.map +1 -1
  55. package/dist/validate.js +4 -6
  56. package/dist/validate.js.map +1 -1
  57. package/package.json +12 -13
  58. package/src/helpers.spec.ts +20 -9
  59. package/src/helpers.ts +14 -0
  60. package/src/index.ts +2 -0
  61. package/src/mime-types.spec.ts +14 -0
  62. package/src/mime-types.ts +336 -0
  63. package/src/server-manager.ts +6 -1
  64. package/src/static-server-manager.spec.ts +226 -0
  65. package/src/static-server-manager.ts +89 -0
  66. package/types/helpers.d.ts +12 -0
  67. package/types/helpers.d.ts.map +1 -1
  68. package/types/index.d.ts +2 -0
  69. package/types/index.d.ts.map +1 -1
  70. package/types/mime-types.d.ts +305 -0
  71. package/types/mime-types.d.ts.map +1 -0
  72. package/types/mime-types.spec.d.ts +2 -0
  73. package/types/mime-types.spec.d.ts.map +1 -0
  74. package/types/server-manager.d.ts +5 -4
  75. package/types/server-manager.d.ts.map +1 -1
  76. package/types/static-server-manager.d.ts +20 -0
  77. package/types/static-server-manager.d.ts.map +1 -0
  78. package/types/static-server-manager.spec.d.ts +2 -0
  79. package/types/static-server-manager.spec.d.ts.map +1 -0
package/src/helpers.ts CHANGED
@@ -4,6 +4,7 @@ import { HttpAuthenticationSettings } from './http-authentication-settings'
4
4
  import { RestApi } from '@furystack/rest'
5
5
  import { ApiManager, ImplementApiOptions } from './api-manager'
6
6
  import { DefaultSession } from './models/default-session'
7
+ import { StaticServerManager, StaticServerOptions } from './static-server-manager'
7
8
 
8
9
  /**
9
10
  * Sets up the @furystack/rest-service with the provided settings
@@ -26,3 +27,16 @@ export const useHttpAuthentication = <TUser extends User, TSession extends Defau
26
27
  injector: Injector,
27
28
  settings?: Partial<HttpAuthenticationSettings<TUser, TSession>>,
28
29
  ) => injector.setExplicitInstance({ ...new HttpAuthenticationSettings(), ...settings }, HttpAuthenticationSettings)
30
+
31
+ /**
32
+ * Sets up a static file server
33
+ *
34
+ * @param options The settings for the static file server
35
+ * @param options.injector The Injector instance
36
+ * @param options.settings Settings for the static file server
37
+ * @returns a promise that resolves when the server is ready
38
+ */
39
+ export const useStaticFiles = (options: { injector: Injector } & StaticServerOptions) => {
40
+ const { injector, ...settings } = options
41
+ return injector.getInstance(StaticServerManager).addStaticSite(settings)
42
+ }
package/src/index.ts CHANGED
@@ -14,3 +14,5 @@ export * from './endpoint-generators'
14
14
  export * from './schema-validator'
15
15
  export * from './request-action-implementation'
16
16
  export * from './validate'
17
+ export * from './mime-types'
18
+ export * from './static-server-manager'
@@ -0,0 +1,14 @@
1
+ import { getMimeForFile } from './mime-types'
2
+ describe('MIME Types', () => {
3
+ it('Should return a default fallback', () => {
4
+ expect(getMimeForFile('test.alma')).toBe('application/octet-stream')
5
+ })
6
+
7
+ it('Should return a value from a supported list', () => {
8
+ expect(getMimeForFile('asd/123/test.mp4')).toBe('video/mp4')
9
+ })
10
+
11
+ it('Should return a value from a wildcarded entry list', () => {
12
+ expect(getMimeForFile('asd/123/test.asdxml')).toBe('text/xml')
13
+ })
14
+ })
@@ -0,0 +1,336 @@
1
+ import path from 'path'
2
+
3
+ export const mimeTypes = {
4
+ 'application/andrew-inset': ['ez'],
5
+ 'application/applixware': ['aw'],
6
+ 'application/atom+xml': ['atom'],
7
+ 'application/atomcat+xml': ['atomcat'],
8
+ 'application/atomdeleted+xml': ['atomdeleted'],
9
+ 'application/atomsvc+xml': ['atomsvc'],
10
+ 'application/atsc-dwd+xml': ['dwd'],
11
+ 'application/atsc-held+xml': ['held'],
12
+ 'application/atsc-rsat+xml': ['rsat'],
13
+ 'application/bdoc': ['bdoc'],
14
+ 'application/calendar+xml': ['xcs'],
15
+ 'application/ccxml+xml': ['ccxml'],
16
+ 'application/cdfx+xml': ['cdfx'],
17
+ 'application/cdmi-capability': ['cdmia'],
18
+ 'application/cdmi-container': ['cdmic'],
19
+ 'application/cdmi-domain': ['cdmid'],
20
+ 'application/cdmi-object': ['cdmio'],
21
+ 'application/cdmi-queue': ['cdmiq'],
22
+ 'application/cu-seeme': ['cu'],
23
+ 'application/dash+xml': ['mpd'],
24
+ 'application/davmount+xml': ['davmount'],
25
+ 'application/docbook+xml': ['dbk'],
26
+ 'application/dssc+der': ['dssc'],
27
+ 'application/dssc+xml': ['xdssc'],
28
+ 'application/ecmascript': ['es', 'ecma'],
29
+ 'application/emma+xml': ['emma'],
30
+ 'application/emotionml+xml': ['emotionml'],
31
+ 'application/epub+zip': ['epub'],
32
+ 'application/exi': ['exi'],
33
+ 'application/express': ['exp'],
34
+ 'application/fdt+xml': ['fdt'],
35
+ 'application/font-tdpfr': ['pfr'],
36
+ 'application/geo+json': ['geojson'],
37
+ 'application/gml+xml': ['gml'],
38
+ 'application/gpx+xml': ['gpx'],
39
+ 'application/gxf': ['gxf'],
40
+ 'application/gzip': ['gz'],
41
+ 'application/hjson': ['hjson'],
42
+ 'application/hyperstudio': ['stk'],
43
+ 'application/inkml+xml': ['ink', 'inkml'],
44
+ 'application/ipfix': ['ipfix'],
45
+ 'application/its+xml': ['its'],
46
+ 'application/java-archive': ['jar', 'war', 'ear'],
47
+ 'application/java-serialized-object': ['ser'],
48
+ 'application/java-vm': ['class'],
49
+ 'application/javascript': ['js', 'mjs'],
50
+ 'application/json': ['json', 'map'],
51
+ 'application/json5': ['json5'],
52
+ 'application/jsonml+json': ['jsonml'],
53
+ 'application/ld+json': ['jsonld'],
54
+ 'application/lgr+xml': ['lgr'],
55
+ 'application/lost+xml': ['lostxml'],
56
+ 'application/mac-binhex40': ['hqx'],
57
+ 'application/mac-compactpro': ['cpt'],
58
+ 'application/mads+xml': ['mads'],
59
+ 'application/manifest+json': ['webmanifest'],
60
+ 'application/marc': ['mrc'],
61
+ 'application/marcxml+xml': ['mrcx'],
62
+ 'application/mathematica': ['ma', 'nb', 'mb'],
63
+ 'application/mathml+xml': ['mathml'],
64
+ 'application/mbox': ['mbox'],
65
+ 'application/mediaservercontrol+xml': ['mscml'],
66
+ 'application/metalink+xml': ['metalink'],
67
+ 'application/metalink4+xml': ['meta4'],
68
+ 'application/mets+xml': ['mets'],
69
+ 'application/mmt-aei+xml': ['maei'],
70
+ 'application/mmt-usd+xml': ['musd'],
71
+ 'application/mods+xml': ['mods'],
72
+ 'application/mp21': ['m21', 'mp21'],
73
+ 'application/mp4': ['mp4s', 'm4p'],
74
+ 'application/msword': ['doc', 'dot'],
75
+ 'application/mxf': ['mxf'],
76
+ 'application/n-quads': ['nq'],
77
+ 'application/n-triples': ['nt'],
78
+ 'application/node': ['cjs'],
79
+ 'application/octet-stream': [
80
+ 'bin',
81
+ 'dms',
82
+ 'lrf',
83
+ 'mar',
84
+ 'so',
85
+ 'dist',
86
+ 'distz',
87
+ 'pkg',
88
+ 'bpk',
89
+ 'dump',
90
+ 'elc',
91
+ 'deploy',
92
+ 'exe',
93
+ 'dll',
94
+ 'deb',
95
+ 'dmg',
96
+ 'iso',
97
+ 'img',
98
+ 'msi',
99
+ 'msp',
100
+ 'msm',
101
+ 'buffer',
102
+ ],
103
+ 'application/oda': ['oda'],
104
+ 'application/oebps-package+xml': ['opf'],
105
+ 'application/ogg': ['ogx'],
106
+ 'application/omdoc+xml': ['omdoc'],
107
+ 'application/onenote': ['onetoc', 'onetoc2', 'onetmp', 'onepkg'],
108
+ 'application/oxps': ['oxps'],
109
+ 'application/p2p-overlay+xml': ['relo'],
110
+ 'application/patch-ops-error+xml': ['xer'],
111
+ 'application/pdf': ['pdf'],
112
+ 'application/pgp-encrypted': ['pgp'],
113
+ 'application/pgp-signature': ['asc', 'sig'],
114
+ 'application/pics-rules': ['prf'],
115
+ 'application/pkcs10': ['p10'],
116
+ 'application/pkcs7-mime': ['p7m', 'p7c'],
117
+ 'application/pkcs7-signature': ['p7s'],
118
+ 'application/pkcs8': ['p8'],
119
+ 'application/pkix-attr-cert': ['ac'],
120
+ 'application/pkix-cert': ['cer'],
121
+ 'application/pkix-crl': ['crl'],
122
+ 'application/pkix-pkipath': ['pkipath'],
123
+ 'application/pkixcmp': ['pki'],
124
+ 'application/pls+xml': ['pls'],
125
+ 'application/postscript': ['ai', 'eps', 'ps'],
126
+ 'application/provenance+xml': ['provx'],
127
+ 'application/pskc+xml': ['pskcxml'],
128
+ 'application/raml+yaml': ['raml'],
129
+ 'application/rdf+xml': ['rdf', 'owl'],
130
+ 'application/reginfo+xml': ['rif'],
131
+ 'application/relax-ng-compact-syntax': ['rnc'],
132
+ 'application/resource-lists+xml': ['rl'],
133
+ 'application/resource-lists-diff+xml': ['rld'],
134
+ 'application/rls-services+xml': ['rs'],
135
+ 'application/route-apd+xml': ['rapd'],
136
+ 'application/route-s-tsid+xml': ['sls'],
137
+ 'application/route-usd+xml': ['rusd'],
138
+ 'application/rpki-ghostbusters': ['gbr'],
139
+ 'application/rpki-manifest': ['mft'],
140
+ 'application/rpki-roa': ['roa'],
141
+ 'application/rsd+xml': ['rsd'],
142
+ 'application/rss+xml': ['rss'],
143
+ 'application/rtf': ['rtf'],
144
+ 'application/sbml+xml': ['sbml'],
145
+ 'application/scvp-cv-request': ['scq'],
146
+ 'application/scvp-cv-response': ['scs'],
147
+ 'application/scvp-vp-request': ['spq'],
148
+ 'application/scvp-vp-response': ['spp'],
149
+ 'application/sdp': ['sdp'],
150
+ 'application/senml+xml': ['senmlx'],
151
+ 'application/sensml+xml': ['sensmlx'],
152
+ 'application/set-payment-initiation': ['setpay'],
153
+ 'application/set-registration-initiation': ['setreg'],
154
+ 'application/shf+xml': ['shf'],
155
+ 'application/sieve': ['siv', 'sieve'],
156
+ 'application/smil+xml': ['smi', 'smil'],
157
+ 'application/sparql-query': ['rq'],
158
+ 'application/sparql-results+xml': ['srx'],
159
+ 'application/srgs': ['gram'],
160
+ 'application/srgs+xml': ['grxml'],
161
+ 'application/sru+xml': ['sru'],
162
+ 'application/ssdl+xml': ['ssdl'],
163
+ 'application/ssml+xml': ['ssml'],
164
+ 'application/swid+xml': ['swidtag'],
165
+ 'application/tei+xml': ['tei', 'teicorpus'],
166
+ 'application/thraud+xml': ['tfi'],
167
+ 'application/timestamped-data': ['tsd'],
168
+ 'application/toml': ['toml'],
169
+ 'application/trig': ['trig'],
170
+ 'application/ttml+xml': ['ttml'],
171
+ 'application/ubjson': ['ubj'],
172
+ 'application/urc-ressheet+xml': ['rsheet'],
173
+ 'application/urc-targetdesc+xml': ['td'],
174
+ 'application/voicexml+xml': ['vxml'],
175
+ 'application/wasm': ['wasm'],
176
+ 'application/widget': ['wgt'],
177
+ 'application/winhlp': ['hlp'],
178
+ 'application/wsdl+xml': ['wsdl'],
179
+ 'application/wspolicy+xml': ['wspolicy'],
180
+ 'application/xaml+xml': ['xaml'],
181
+ 'application/xcap-att+xml': ['xav'],
182
+ 'application/xcap-caps+xml': ['xca'],
183
+ 'application/xcap-diff+xml': ['xdf'],
184
+ 'application/xcap-el+xml': ['xel'],
185
+ 'application/xcap-ns+xml': ['xns'],
186
+ 'application/xenc+xml': ['xenc'],
187
+ 'application/xhtml+xml': ['xhtml', 'xht'],
188
+ 'application/xliff+xml': ['xlf'],
189
+ 'application/xml': ['xml', 'xsl', 'xsd', 'rng'],
190
+ 'application/xml-dtd': ['dtd'],
191
+ 'application/xop+xml': ['xop'],
192
+ 'application/xproc+xml': ['xpl'],
193
+ 'application/xslt+xml': ['(.)+xsl', 'xslt'],
194
+ 'application/xspf+xml': ['xspf'],
195
+ 'application/xv+xml': ['mxml', 'xhvml', 'xvml', 'xvm'],
196
+ 'application/yang': ['yang'],
197
+ 'application/yin+xml': ['yin'],
198
+ 'application/zip': ['zip'],
199
+ 'audio/3gpp': ['(.)+3gpp'],
200
+ 'audio/adpcm': ['adp'],
201
+ 'audio/amr': ['amr'],
202
+ 'audio/basic': ['au', 'snd'],
203
+ 'audio/midi': ['mid', 'midi', 'kar', 'rmi'],
204
+ 'audio/mobile-xmf': ['mxmf'],
205
+ 'audio/mp3': ['(.)+mp3'],
206
+ 'audio/mp4': ['m4a', 'mp4a'],
207
+ 'audio/mpeg': ['mpga', 'mp2', 'mp2a', 'mp3', 'm2a', 'm3a'],
208
+ 'audio/ogg': ['oga', 'ogg', 'spx', 'opus'],
209
+ 'audio/s3m': ['s3m'],
210
+ 'audio/silk': ['sil'],
211
+ 'audio/wav': ['wav'],
212
+ 'audio/wave': ['(.)+wav'],
213
+ 'audio/webm': ['weba'],
214
+ 'audio/xm': ['xm'],
215
+ 'font/collection': ['ttc'],
216
+ 'font/otf': ['otf'],
217
+ 'font/ttf': ['ttf'],
218
+ 'font/woff': ['woff'],
219
+ 'font/woff2': ['woff2'],
220
+ 'image/aces': ['exr'],
221
+ 'image/apng': ['apng'],
222
+ 'image/avif': ['avif'],
223
+ 'image/bmp': ['bmp'],
224
+ 'image/cgm': ['cgm'],
225
+ 'image/dicom-rle': ['drle'],
226
+ 'image/emf': ['emf'],
227
+ 'image/fits': ['fits'],
228
+ 'image/g3fax': ['g3'],
229
+ 'image/gif': ['gif'],
230
+ 'image/heic': ['heic'],
231
+ 'image/heic-sequence': ['heics'],
232
+ 'image/heif': ['heif'],
233
+ 'image/heif-sequence': ['heifs'],
234
+ 'image/hej2k': ['hej2'],
235
+ 'image/hsj2': ['hsj2'],
236
+ 'image/ief': ['ief'],
237
+ 'image/jls': ['jls'],
238
+ 'image/jp2': ['jp2', 'jpg2'],
239
+ 'image/jpeg': ['jpeg', 'jpg', 'jpe'],
240
+ 'image/jph': ['jph'],
241
+ 'image/jphc': ['jhc'],
242
+ 'image/jpm': ['jpm'],
243
+ 'image/jpx': ['jpx', 'jpf'],
244
+ 'image/jxr': ['jxr'],
245
+ 'image/jxra': ['jxra'],
246
+ 'image/jxrs': ['jxrs'],
247
+ 'image/jxs': ['jxs'],
248
+ 'image/jxsc': ['jxsc'],
249
+ 'image/jxsi': ['jxsi'],
250
+ 'image/jxss': ['jxss'],
251
+ 'image/ktx': ['ktx'],
252
+ 'image/ktx2': ['ktx2'],
253
+ 'image/png': ['png'],
254
+ 'image/sgi': ['sgi'],
255
+ 'image/svg+xml': ['svg', 'svgz'],
256
+ 'image/t38': ['t38'],
257
+ 'image/tiff': ['tif', 'tiff'],
258
+ 'image/tiff-fx': ['tfx'],
259
+ 'image/webp': ['webp'],
260
+ 'image/wmf': ['wmf'],
261
+ 'message/disposition-notification': ['disposition-notification'],
262
+ 'message/global': ['u8msg'],
263
+ 'message/global-delivery-status': ['u8dsn'],
264
+ 'message/global-disposition-notification': ['u8mdn'],
265
+ 'message/global-headers': ['u8hdr'],
266
+ 'message/rfc822': ['eml', 'mime'],
267
+ 'model/3mf': ['3mf'],
268
+ 'model/gltf+json': ['gltf'],
269
+ 'model/gltf-binary': ['glb'],
270
+ 'model/iges': ['igs', 'iges'],
271
+ 'model/mesh': ['msh', 'mesh', 'silo'],
272
+ 'model/mtl': ['mtl'],
273
+ 'model/obj': ['obj'],
274
+ 'model/step+xml': ['stpx'],
275
+ 'model/step+zip': ['stpz'],
276
+ 'model/step-xml+zip': ['stpxz'],
277
+ 'model/stl': ['stl'],
278
+ 'model/vrml': ['wrl', 'vrml'],
279
+ 'model/x3d+binary': ['(.)+x3db', 'x3dbz'],
280
+ 'model/x3d+fastinfoset': ['x3db'],
281
+ 'model/x3d+vrml': ['(.)+x3dv', 'x3dvz'],
282
+ 'model/x3d+xml': ['x3d', 'x3dz'],
283
+ 'model/x3d-vrml': ['x3dv'],
284
+ 'text/cache-manifest': ['appcache', 'manifest'],
285
+ 'text/calendar': ['ics', 'ifb'],
286
+ 'text/coffeescript': ['coffee', 'litcoffee'],
287
+ 'text/css': ['css'],
288
+ 'text/csv': ['csv'],
289
+ 'text/html': ['html', 'htm', 'shtml'],
290
+ 'text/jade': ['jade'],
291
+ 'text/jsx': ['jsx'],
292
+ 'text/less': ['less'],
293
+ 'text/markdown': ['markdown', 'md'],
294
+ 'text/mathml': ['mml'],
295
+ 'text/mdx': ['mdx'],
296
+ 'text/n3': ['n3'],
297
+ 'text/plain': ['txt', 'text', 'conf', 'def', 'list', 'log', 'in', 'ini'],
298
+ 'text/richtext': ['rtx'],
299
+ 'text/rtf': ['(.)+rtf'],
300
+ 'text/sgml': ['sgml', 'sgm'],
301
+ 'text/shex': ['shex'],
302
+ 'text/slim': ['slim', 'slm'],
303
+ 'text/spdx': ['spdx'],
304
+ 'text/stylus': ['stylus', 'styl'],
305
+ 'text/tab-separated-values': ['tsv'],
306
+ 'text/troff': ['t', 'tr', 'roff', 'man', 'me', 'ms'],
307
+ 'text/turtle': ['ttl'],
308
+ 'text/uri-list': ['uri', 'uris', 'urls'],
309
+ 'text/vcard': ['vcard'],
310
+ 'text/vtt': ['vtt'],
311
+ 'text/xml': ['(.)+xml'],
312
+ 'text/yaml': ['yaml', 'yml'],
313
+ 'video/3gpp': ['3gp', '3gpp'],
314
+ 'video/3gpp2': ['3g2'],
315
+ 'video/h261': ['h261'],
316
+ 'video/h263': ['h263'],
317
+ 'video/h264': ['h264'],
318
+ 'video/iso.segment': ['m4s'],
319
+ 'video/jpeg': ['jpgv'],
320
+ 'video/jpm': ['(.)+jpm', 'jpgm'],
321
+ 'video/mj2': ['mj2', 'mjp2'],
322
+ 'video/mp2t': ['ts'],
323
+ 'video/mp4': ['mp4', 'mp4v', 'mpg4'],
324
+ 'video/mpeg': ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v'],
325
+ 'video/ogg': ['ogv'],
326
+ 'video/quicktime': ['qt', 'mov'],
327
+ 'video/webm': ['webm'],
328
+ }
329
+
330
+ export const getMimeForFile = (file: string) => {
331
+ const ext = path.extname(file)
332
+ return (
333
+ Object.entries(mimeTypes).find(([, values]) => values.some((value) => ext.match(`^.${value}$`)))?.[0] ||
334
+ 'application/octet-stream'
335
+ )
336
+ }
@@ -15,9 +15,14 @@ export interface OnRequest {
15
15
  res: ServerResponse
16
16
  }
17
17
 
18
+ export interface ServerApi {
19
+ shouldExec: (options: OnRequest) => boolean
20
+ onRequest: (options: OnRequest) => void
21
+ }
22
+
18
23
  export interface ServerRecord {
19
24
  server: Server
20
- apis: Array<{ shouldExec: (options: OnRequest) => boolean; onRequest: (options: OnRequest) => void }>
25
+ apis: ServerApi[]
21
26
  }
22
27
 
23
28
  @Injectable({ lifetime: 'singleton' })
@@ -0,0 +1,226 @@
1
+ import { Injector } from '@furystack/inject'
2
+ import { sleepAsync, usingAsync } from '@furystack/utils'
3
+ import got, { RequestError } from 'got'
4
+ import { ServerManager } from './server-manager'
5
+ import { StaticServerManager } from './static-server-manager'
6
+
7
+ describe('StaticServerManager', () => {
8
+ describe('Top level routing', () => {
9
+ it('Should return a 404 without fallback', async () => {
10
+ await usingAsync(new Injector(), async (injector) => {
11
+ const staticServerManager = injector.getInstance(StaticServerManager)
12
+
13
+ await staticServerManager.addStaticSite({
14
+ baseUrl: '/',
15
+ path: '.',
16
+ port: 1234,
17
+ })
18
+
19
+ try {
20
+ await got.get('http://localhost:1234/not-found.html')
21
+ } catch (error) {
22
+ expect(error).toBeInstanceOf(RequestError)
23
+ const requestError: RequestError = error as RequestError
24
+
25
+ expect(requestError.response?.statusCode).toBe(404)
26
+ expect(requestError.response?.headers['content-type']).toBe('text/plain')
27
+ expect(requestError.response?.body).toBe('Not found')
28
+ }
29
+ })
30
+ })
31
+
32
+ it('Should return a fallback', async () => {
33
+ await usingAsync(new Injector(), async (injector) => {
34
+ const staticServerManager = injector.getInstance(StaticServerManager)
35
+
36
+ await staticServerManager.addStaticSite({
37
+ baseUrl: '/',
38
+ path: '.',
39
+ fallback: 'package.json',
40
+ port: 1234,
41
+ headers: {
42
+ 'custom-header': 'custom-value',
43
+ },
44
+ })
45
+
46
+ const result = await got.get('http://localhost:1234/not-found.html')
47
+
48
+ expect(result.headers['content-type']).toBe('application/json')
49
+ expect(result.headers['custom-header']).toBe('custom-value')
50
+ })
51
+ })
52
+
53
+ it('Should return a defined file from a root directory', async () => {
54
+ await usingAsync(new Injector(), async (injector) => {
55
+ const staticServerManager = injector.getInstance(StaticServerManager)
56
+
57
+ await staticServerManager.addStaticSite({
58
+ baseUrl: '/',
59
+ path: '.',
60
+ port: 1234,
61
+ headers: {
62
+ 'custom-header': 'custom-value',
63
+ },
64
+ })
65
+
66
+ const result = await got.get('http://localhost:1234/README.md')
67
+
68
+ expect(result.headers['content-type']).toBe('text/markdown')
69
+ expect(result.headers['custom-header']).toBe('custom-value')
70
+ })
71
+ })
72
+
73
+ it('Should return a defined file from a subdirectory', async () => {
74
+ await usingAsync(new Injector(), async (injector) => {
75
+ const staticServerManager = injector.getInstance(StaticServerManager)
76
+
77
+ await staticServerManager.addStaticSite({
78
+ baseUrl: '/',
79
+ path: '.',
80
+ port: 1234,
81
+ })
82
+
83
+ const result = await got.get('http://localhost:1234/packages/utils/README.md')
84
+
85
+ expect(result.headers['content-type']).toBe('text/markdown')
86
+ })
87
+ })
88
+ })
89
+
90
+ describe('Non-top level routing', () => {
91
+ it('Should not handle a request when the path is not matching', async () => {
92
+ await usingAsync(new Injector(), async (injector) => {
93
+ const staticServerManager = injector.getInstance(StaticServerManager)
94
+
95
+ await staticServerManager.addStaticSite({
96
+ baseUrl: '/bundle',
97
+ path: '.',
98
+ port: 1234,
99
+ })
100
+
101
+ const server = [...injector.getInstance(ServerManager).servers.values()][0]
102
+
103
+ server.apis[0].onRequest = jest.fn()
104
+
105
+ got.get('http://localhost:1234/bundleToAnotherFolder/not-found.html')
106
+
107
+ await sleepAsync(100)
108
+
109
+ expect(server.apis[0].onRequest).not.toHaveBeenCalled()
110
+ })
111
+ })
112
+
113
+ it('Should return a 404 without fallback', async () => {
114
+ await usingAsync(new Injector(), async (injector) => {
115
+ const staticServerManager = injector.getInstance(StaticServerManager)
116
+
117
+ await staticServerManager.addStaticSite({
118
+ baseUrl: '/bundle',
119
+ path: '.',
120
+ port: 1234,
121
+ })
122
+
123
+ try {
124
+ await got.get('http://localhost:1234/bundle/not-found.html')
125
+ } catch (error) {
126
+ expect(error).toBeInstanceOf(RequestError)
127
+ const requestError: RequestError = error as RequestError
128
+
129
+ expect(requestError.response?.statusCode).toBe(404)
130
+ expect(requestError.response?.headers['content-type']).toBe('text/plain')
131
+ expect(requestError.response?.body).toBe('Not found')
132
+ }
133
+ })
134
+ })
135
+
136
+ it('Should return a fallback', async () => {
137
+ await usingAsync(new Injector(), async (injector) => {
138
+ const staticServerManager = injector.getInstance(StaticServerManager)
139
+
140
+ await staticServerManager.addStaticSite({
141
+ baseUrl: '/bundle',
142
+ path: '.',
143
+ fallback: 'package.json',
144
+ port: 1234,
145
+ })
146
+
147
+ const result = await got.get('http://localhost:1234/bundle/not-found.html')
148
+
149
+ expect(result.headers['content-type']).toBe('application/json')
150
+ })
151
+ })
152
+
153
+ it('Should return a defined file from a root directory', async () => {
154
+ await usingAsync(new Injector(), async (injector) => {
155
+ const staticServerManager = injector.getInstance(StaticServerManager)
156
+
157
+ await staticServerManager.addStaticSite({
158
+ baseUrl: '/',
159
+ path: '.',
160
+ port: 1234,
161
+ })
162
+
163
+ const result = await got.get('http://localhost:1234/README.md')
164
+
165
+ expect(result.headers['content-type']).toBe('text/markdown')
166
+ })
167
+ })
168
+
169
+ it('Should return a defined file from a subdirectory', async () => {
170
+ await usingAsync(new Injector(), async (injector) => {
171
+ const staticServerManager = injector.getInstance(StaticServerManager)
172
+
173
+ await staticServerManager.addStaticSite({
174
+ baseUrl: '/',
175
+ path: '.',
176
+ port: 1234,
177
+ })
178
+
179
+ const result = await got.get('http://localhost:1234/packages/utils/README.md')
180
+
181
+ expect(result.headers['content-type']).toBe('text/markdown')
182
+ })
183
+ })
184
+ })
185
+
186
+ describe('shouldExec', () => {
187
+ it('Should NOT match for requests with not defined method', () => {
188
+ const staticServerManager = new StaticServerManager()
189
+ expect(staticServerManager.shouldExec('/')({ req: { url: '/' } })).toBe(false)
190
+ })
191
+
192
+ it('Should NOT match for non-GET requests', () => {
193
+ const staticServerManager = new StaticServerManager()
194
+ expect(staticServerManager.shouldExec('/')({ req: { method: 'POST', url: '/' } })).toBe(false)
195
+ })
196
+ ;[
197
+ ['/', '/'],
198
+ ['/', '/index.html'],
199
+ ['/', '/subdir'],
200
+ ['/', '/subdir/'],
201
+ ['/', '/subdir/file.js'],
202
+ ['/subdir', '/subdir'],
203
+ ['/subdir', '/subdir/'],
204
+ ['/subdir', '/subdir/file.js'],
205
+ ['/subdir', '/subdir/s2/file.js'],
206
+ ].forEach(([root, url]) =>
207
+ it(`Should match for '${root}' root and '${url}' url`, () => {
208
+ const staticServerManager = new StaticServerManager()
209
+ const shouldExec = staticServerManager.shouldExec(root)({ req: { method: 'GET', url } })
210
+ expect(shouldExec).toBe(true)
211
+ }),
212
+ )
213
+
214
+ it('Should not exec different paths for non-top level root directory', () => {
215
+ const staticServerManager = new StaticServerManager()
216
+ expect(staticServerManager.shouldExec('/subdir')({ req: { method: 'GET', url: '/' } })).toBe(false)
217
+ expect(staticServerManager.shouldExec('/subdir')({ req: { method: 'GET', url: '/other/index.html' } })).toBe(
218
+ false,
219
+ )
220
+ expect(staticServerManager.shouldExec('/subdir')({ req: { method: 'GET', url: '/subdir2' } })).toBe(false)
221
+ expect(staticServerManager.shouldExec('/subdir')({ req: { method: 'GET', url: '/subdir2/index.html' } })).toBe(
222
+ false,
223
+ )
224
+ })
225
+ })
226
+ })