@logux/server 0.10.1 → 0.10.5

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.
@@ -247,9 +247,11 @@ interface Authorizer<
247
247
  Data extends object,
248
248
  Headers extends object
249
249
  > {
250
- (ctx: Context<Data, Headers>, action: TypeAction, meta: ServerMeta):
251
- | boolean
252
- | Promise<boolean>
250
+ (
251
+ ctx: Context<Data, Headers>,
252
+ action: Readonly<TypeAction>,
253
+ meta: Readonly<ServerMeta>
254
+ ): boolean | Promise<boolean>
253
255
  }
254
256
 
255
257
  /**
@@ -265,9 +267,11 @@ interface Resender<
265
267
  Data extends object,
266
268
  Headers extends object
267
269
  > {
268
- (ctx: Context<Data, Headers>, action: TypeAction, meta: ServerMeta):
269
- | Resend
270
- | Promise<Resend>
270
+ (
271
+ ctx: Context<Data, Headers>,
272
+ action: Readonly<TypeAction>,
273
+ meta: Readonly<ServerMeta>
274
+ ): Resend | Promise<Resend>
271
275
  }
272
276
 
273
277
  /**
@@ -285,8 +289,8 @@ interface Processor<
285
289
  > {
286
290
  (
287
291
  ctx: Context<Data, Headers>,
288
- action: TypeAction,
289
- meta: ServerMeta
292
+ action: Readonly<TypeAction>,
293
+ meta: Readonly<ServerMeta>
290
294
  ): void | Promise<void>
291
295
  }
292
296
 
@@ -303,7 +307,11 @@ interface ActionFinally<
303
307
  Data extends object,
304
308
  Headers extends object
305
309
  > {
306
- (ctx: Context<Data, Headers>, action: TypeAction, meta: ServerMeta): void
310
+ (
311
+ ctx: Context<Data, Headers>,
312
+ action: Readonly<TypeAction>,
313
+ meta: Readonly<ServerMeta>
314
+ ): void
307
315
  }
308
316
 
309
317
  /**
@@ -315,7 +323,11 @@ interface ActionFinally<
315
323
  * @returns Should action be sent to client.
316
324
  */
317
325
  interface ChannelFilter<Headers extends object> {
318
- (ctx: Context<{}, Headers>, action: Action, meta: ServerMeta): boolean
326
+ (
327
+ ctx: Context<{}, Headers>,
328
+ action: Readonly<Action>,
329
+ meta: Readonly<ServerMeta>
330
+ ): boolean
319
331
  }
320
332
 
321
333
  /**
@@ -334,8 +346,8 @@ interface ChannelAuthorizer<
334
346
  > {
335
347
  (
336
348
  ctx: ChannelContext<Data, ChannelParams, Headers>,
337
- action: SubscribeAction,
338
- meta: ServerMeta
349
+ action: Readonly<SubscribeAction>,
350
+ meta: Readonly<ServerMeta>
339
351
  ): boolean | Promise<boolean>
340
352
  }
341
353
 
@@ -355,8 +367,8 @@ interface FilterCreator<
355
367
  > {
356
368
  (
357
369
  ctx: ChannelContext<Data, ChannelParams, Headers>,
358
- action: SubscribeAction,
359
- meta: ServerMeta
370
+ action: Readonly<SubscribeAction>,
371
+ meta: Readonly<ServerMeta>
360
372
  ): Promise<ChannelFilter<Headers>> | ChannelFilter<Headers> | void
361
373
  }
362
374
 
@@ -376,8 +388,8 @@ interface ChannelLoader<
376
388
  > {
377
389
  (
378
390
  ctx: ChannelContext<Data, ChannelParams, Headers>,
379
- action: SubscribeAction,
380
- meta: ServerMeta
391
+ action: Readonly<SubscribeAction>,
392
+ meta: Readonly<ServerMeta>
381
393
  ): SendBackActions | Promise<SendBackActions>
382
394
  }
383
395
 
@@ -397,8 +409,8 @@ interface ChannelFinally<
397
409
  > {
398
410
  (
399
411
  ctx: ChannelContext<Data, ChannelParams, Headers>,
400
- action: SubscribeAction,
401
- meta: ServerMeta
412
+ action: Readonly<SubscribeAction>,
413
+ meta: Readonly<ServerMeta>
402
414
  ): void
403
415
  }
404
416
 
@@ -418,7 +430,7 @@ interface ChannelUnsubscribe<
418
430
  (
419
431
  ctx: ChannelContext<Data, ChannelParams, Headers>,
420
432
  action: LoguxUnsubscribeAction,
421
- meta: ServerMeta
433
+ meta: Readonly<ServerMeta>
422
434
  ): void
423
435
  }
424
436
 
@@ -464,8 +476,8 @@ type ChannelCallbacks<
464
476
  }
465
477
 
466
478
  interface ActionReporter {
467
- action: Action
468
- meta: ServerMeta
479
+ action: Readonly<Action>
480
+ meta: Readonly<ServerMeta>
469
481
  }
470
482
 
471
483
  interface SubscriptionReporter {
@@ -585,7 +597,7 @@ interface GetProcessor {
585
597
  }
586
598
 
587
599
  interface PostProcessor {
588
- isValid(command: object): false
600
+ isValid(command: object): boolean
589
601
  command(command: object, request: object): Promise<void>
590
602
  }
591
603
 
@@ -817,7 +829,7 @@ export class BaseServer<
817
829
  */
818
830
  on(
819
831
  event: 'error',
820
- listener: (err: Error, action: Action, meta: ServerMeta) => void
832
+ listener: (err: Error, action: Action, meta: Readonly<ServerMeta>) => void
821
833
  ): Unsubscribe
822
834
 
823
835
  /**
@@ -843,7 +855,16 @@ export class BaseServer<
843
855
  * @param listener Action listener.
844
856
  */
845
857
  on(
846
- event: 'preadd' | 'add' | 'clean' | 'backendSent',
858
+ event: 'add' | 'clean' | 'backendSent',
859
+ listener: (action: Action, meta: Readonly<ServerMeta>) => void
860
+ ): Unsubscribe
861
+
862
+ /**
863
+ * @param event The event name.
864
+ * @param listener Action listener.
865
+ */
866
+ on(
867
+ event: 'preadd',
847
868
  listener: (action: Action, meta: ServerMeta) => void
848
869
  ): Unsubscribe
849
870
 
@@ -855,7 +876,7 @@ export class BaseServer<
855
876
  event: 'processed' | 'backendGranted' | 'backendProcessed',
856
877
  listener: (
857
878
  action: Action,
858
- meta: ServerMeta,
879
+ meta: Readonly<ServerMeta>,
859
880
  latencyMilliseconds: number
860
881
  ) => void
861
882
  ): Unsubscribe
@@ -868,7 +889,7 @@ export class BaseServer<
868
889
  event: 'subscribed',
869
890
  listener: (
870
891
  action: LoguxSubscribeAction,
871
- meta: ServerMeta,
892
+ meta: Readonly<ServerMeta>,
872
893
  latencyMilliseconds: number
873
894
  ) => void
874
895
  ): Unsubscribe
@@ -879,7 +900,7 @@ export class BaseServer<
879
900
  */
880
901
  on(
881
902
  event: 'subscribing',
882
- listener: (action: LoguxSubscribeAction, meta: ServerMeta) => void
903
+ listener: (action: LoguxSubscribeAction, meta: Readonly<ServerMeta>) => void
883
904
  ): Unsubscribe
884
905
 
885
906
  /**
@@ -888,7 +909,10 @@ export class BaseServer<
888
909
  */
889
910
  on(
890
911
  event: 'unsubscribed',
891
- listener: (action: LoguxUnsubscribeAction, meta: ServerMeta) => void
912
+ listener: (
913
+ action: LoguxUnsubscribeAction,
914
+ meta: Readonly<ServerMeta>
915
+ ) => void
892
916
  ): Unsubscribe
893
917
 
894
918
  /**
@@ -1058,7 +1082,10 @@ export class BaseServer<
1058
1082
  * @param meta Action’s meta.
1059
1083
  * @returns Promise until new action will be resend to clients and processed.
1060
1084
  */
1061
- process(action: AnyAction, meta?: Partial<ServerMeta>): Promise<ServerMeta>
1085
+ process(
1086
+ action: AnyAction,
1087
+ meta?: Partial<ServerMeta>
1088
+ ): Promise<Readonly<ServerMeta>>
1062
1089
 
1063
1090
  /**
1064
1091
  * Undo action from client.
@@ -14,6 +14,7 @@ import { createHttpServer } from '../create-http-server/index.js'
14
14
  import { ServerClient } from '../server-client/index.js'
15
15
  import { Context } from '../context/index.js'
16
16
 
17
+ const SKIP_PROCESS = Symbol('skipProcess')
17
18
  const RESEND_META = ['channels', 'users', 'clients', 'nodes']
18
19
 
19
20
  function optionError(msg) {
@@ -48,11 +49,15 @@ export async function wasNot403(cb) {
48
49
 
49
50
  function normalizeTypeCallbacks(name, callbacks) {
50
51
  if (callbacks && callbacks.accessAndProcess) {
51
- callbacks.access = (...args) => {
52
+ callbacks.access = (ctx, ...args) => {
52
53
  return wasNot403(async () => {
53
- await callbacks.accessAndProcess(...args)
54
+ await callbacks.accessAndProcess(ctx, ...args)
55
+ ctx[SKIP_PROCESS] = true
54
56
  })
55
57
  }
58
+ callbacks.process = async (ctx, ...args) => {
59
+ if (!ctx[SKIP_PROCESS]) await callbacks.accessAndProcess(ctx, ...args)
60
+ }
56
61
  }
57
62
  if (!callbacks || !callbacks.access) {
58
63
  throw new Error(`${name} must have access callback`)
@@ -373,12 +378,12 @@ export class BaseServer {
373
378
  if (!this.authenticator) {
374
379
  throw new Error('You must set authentication callback by server.auth()')
375
380
  }
376
- this.http = await createHttpServer(this.options)
377
- this.ws = new WebSocket.Server({ server: this.http })
381
+ this.httpServer = await createHttpServer(this.options)
382
+ this.ws = new WebSocket.Server({ server: this.httpServer })
378
383
  if (!this.options.server) {
379
384
  await new Promise((resolve, reject) => {
380
385
  this.ws.on('error', reject)
381
- this.http.listen(this.options.port, this.options.host, resolve)
386
+ this.httpServer.listen(this.options.port, this.options.host, resolve)
382
387
  })
383
388
  }
384
389
  bindControlServer(this, this.httpListener)
@@ -390,12 +395,12 @@ export class BaseServer {
390
395
  this.ws.close()
391
396
  })
392
397
  )
393
- if (this.http) {
398
+ if (this.httpServer) {
394
399
  this.unbind.push(
395
400
  () =>
396
401
  new Promise(resolve => {
397
- this.http.on('close', resolve)
398
- this.http.close()
402
+ this.httpServer.on('close', resolve)
403
+ this.httpServer.close()
399
404
  })
400
405
  )
401
406
  }
@@ -18,7 +18,7 @@ function isValidBody(body) {
18
18
 
19
19
  export function bindControlServer(app, custom) {
20
20
  let masks = app.options.controlMask.split(/,\s*/).map(i => ip.cidrSubnet(i))
21
- app.http.on('request', async (req, res) => {
21
+ app.httpServer.on('request', async (req, res) => {
22
22
  let urlString = req.url
23
23
  if (/^\/\w+%3F/.test(urlString)) urlString = decodeURIComponent(urlString)
24
24
  let reqUrl = new URL(urlString, 'http://localhost')
@@ -222,14 +222,19 @@ function createLogger(options) {
222
222
  )
223
223
  }
224
224
 
225
- function cleanFromKeys(obj, regexp) {
225
+ function cleanFromKeys(obj, regexp, seen) {
226
226
  let result = {}
227
227
  for (let key in obj) {
228
228
  let v = obj[key]
229
229
  if (typeof v === 'string') {
230
230
  result[key] = v.replace(regexp, '[SECRET]')
231
231
  } else if (typeof v === 'object' && !Array.isArray(v) && v !== null) {
232
- result[key] = cleanFromKeys(v, regexp)
232
+ if (seen.includes(v)) {
233
+ throw new Error('Circular reference in action')
234
+ }
235
+ seen.push(v)
236
+ result[key] = cleanFromKeys(v, regexp, seen)
237
+ seen.pop()
233
238
  } else {
234
239
  result[key] = v
235
240
  }
@@ -242,8 +247,9 @@ export function createReporter(options) {
242
247
  function reporter(type, details) {
243
248
  let report = REPORTERS[type](details)
244
249
  let level = report.level || 'info'
250
+ let seen = []
245
251
  reporter.logger[level](
246
- cleanFromKeys(report.details || details || {}, cleanFromLog),
252
+ cleanFromKeys(report.details || details || {}, cleanFromLog, seen),
247
253
  report.msg.replace(cleanFromLog, '[SECRET]')
248
254
  )
249
255
  }
@@ -1,17 +1,4 @@
1
- import {
2
- green,
3
- bgGreen,
4
- yellow,
5
- bgYellow,
6
- red,
7
- bgRed,
8
- black,
9
- white,
10
- gray,
11
- dim,
12
- bold,
13
- options as colorette
14
- } from 'colorette'
1
+ import { createColors } from 'nanocolors'
15
2
  import stripAnsi from 'strip-ansi'
16
3
  import yyyymmdd from 'yyyy-mm-dd'
17
4
  import path from 'path'
@@ -183,25 +170,8 @@ function prettyStackTrace(c, stack, basepath) {
183
170
  }
184
171
 
185
172
  export function humanFormatter(options) {
186
- let c = {
187
- green,
188
- bgGreen,
189
- yellow,
190
- bgYellow,
191
- red,
192
- bgRed,
193
- black,
194
- white,
195
- gray,
196
- dim,
197
- bold
198
- }
199
- this.color = true
200
- if (options.color === false || !colorette.enabled) {
201
- this.color = false
202
- let empty = str => str
203
- for (let color in c) c[color] = empty
204
- }
173
+ let c = createColors(options.color)
174
+ this.color = c.isColorSupported
205
175
  let basepath = options.basepath || process.cwd()
206
176
  if (basepath.slice(-1) !== path.sep) basepath += path.sep
207
177
  this.basepath = basepath
@@ -1,4 +1,4 @@
1
- import { bold, cyan, yellow, green, red } from 'colorette'
1
+ import { bold, cyan, yellow, green, red } from 'nanocolors'
2
2
  import dotenv from 'dotenv'
3
3
 
4
4
  export function loadOptions(spec, process, env) {
@@ -31,11 +31,8 @@ export function loadOptions(spec, process, env) {
31
31
  key.startsWith(spec.envPrefix)
32
32
  )
33
33
  )
34
- envArgs = parseValues(
35
- spec,
36
- mapArgs(Object.assign(envArgs, dotenvArgs), namesMap)
37
- )
38
- return [null, Object.assign(envArgs, cliArgs)]
34
+ envArgs = parseValues(spec, mapArgs({ ...envArgs, ...dotenvArgs }, namesMap))
35
+ return [null, { ...envArgs, ...cliArgs }]
39
36
  }
40
37
 
41
38
  function gatherCliArgs(argv) {
@@ -0,0 +1,257 @@
1
+ import { resolve } from 'path'
2
+
3
+ import { loadOptions, oneOf, number } from './index.js'
4
+
5
+ function fakeProcess(argv, env = {}) {
6
+ return { argv, env }
7
+ }
8
+
9
+ describe('loadOptions', () => {
10
+ it('returns help', () => {
11
+ let [help, options] = loadOptions(
12
+ {
13
+ options: {
14
+ port: {
15
+ description: 'port',
16
+ parse: number
17
+ }
18
+ },
19
+ examples: ['$0']
20
+ },
21
+ fakeProcess(['node', 'test/test.js', '--help'])
22
+ )
23
+
24
+ expect(help).toMatchSnapshot()
25
+ expect(options).toBeNull()
26
+ })
27
+
28
+ it('uses CLI args for options', () => {
29
+ let [, options] = loadOptions(
30
+ {
31
+ options: {
32
+ port: {
33
+ description: 'port',
34
+ parse: number
35
+ }
36
+ }
37
+ },
38
+ fakeProcess(['', '--port', '1337'])
39
+ )
40
+ expect(options.port).toEqual(1337)
41
+ })
42
+
43
+ it('uses env for options', () => {
44
+ let [, options] = loadOptions(
45
+ {
46
+ options: {
47
+ port: {
48
+ description: 'port',
49
+ parse: number
50
+ }
51
+ },
52
+ envPrefix: 'LOGUX'
53
+ },
54
+ fakeProcess([], {
55
+ LOGUX_PORT: '31337'
56
+ }),
57
+ {}
58
+ )
59
+
60
+ expect(options.port).toEqual(31337)
61
+ })
62
+
63
+ it('uses dotenv file for options', () => {
64
+ let [, options] = loadOptions(
65
+ {
66
+ options: {
67
+ port: {
68
+ description: 'port',
69
+ parse: number
70
+ }
71
+ },
72
+ envPrefix: 'LOGUX'
73
+ },
74
+ fakeProcess([], {}),
75
+ {
76
+ path: resolve(process.cwd(), 'options-loader/test.env')
77
+ }
78
+ )
79
+
80
+ expect(options.port).toEqual(31337)
81
+ })
82
+
83
+ it('composes correct env and CLI names for argument with complex name', () => {
84
+ let [, options] = loadOptions(
85
+ {
86
+ options: {
87
+ somePort: {
88
+ description: 'port',
89
+ parse: number
90
+ }
91
+ },
92
+ envPrefix: 'LOGUX'
93
+ },
94
+ fakeProcess(['--some-port', '1'], {
95
+ LOGUX_SOME_PORT: '1'
96
+ }),
97
+ {}
98
+ )
99
+
100
+ expect(options.somePort).toEqual(1)
101
+ })
102
+
103
+ it('uses combined options', () => {
104
+ let [, options] = loadOptions(
105
+ {
106
+ options: {
107
+ key: {
108
+ description: 'port'
109
+ },
110
+ cert: {
111
+ description: 'cert'
112
+ }
113
+ },
114
+ envPrefix: 'LOGUX'
115
+ },
116
+ fakeProcess(['', '--key', './key.pem'], { LOGUX_CERT: './cert.pem' })
117
+ )
118
+
119
+ expect(options.cert).toEqual('./cert.pem')
120
+ expect(options.key).toEqual('./key.pem')
121
+ })
122
+
123
+ it('uses arg and env in given priority', () => {
124
+ let optionsSpec = {
125
+ options: {
126
+ port: {
127
+ description: 'port',
128
+ parse: number
129
+ },
130
+ key: {
131
+ description: 'key'
132
+ },
133
+ cert: {
134
+ description: 'cert'
135
+ }
136
+ },
137
+ envPrefix: 'LOGUX'
138
+ }
139
+
140
+ let [, options1] = loadOptions(
141
+ optionsSpec,
142
+ fakeProcess(['', '--port', '3'], { LOGUX_PORT: '2' }),
143
+ undefined
144
+ )
145
+ let [, options2] = loadOptions(
146
+ optionsSpec,
147
+ fakeProcess([], { LOGUX_PORT: '2' }),
148
+ undefined
149
+ )
150
+
151
+ expect(options1.port).toEqual(3)
152
+ expect(options2.port).toEqual(2)
153
+ })
154
+
155
+ it('parses aliases', () => {
156
+ let [, options] = loadOptions(
157
+ {
158
+ options: {
159
+ port: {
160
+ alias: 'p',
161
+ description: 'port'
162
+ }
163
+ }
164
+ },
165
+ fakeProcess(['', '-p', '1'])
166
+ )
167
+ expect(options.port).toEqual('1')
168
+ })
169
+
170
+ it('parses multiple args', () => {
171
+ let [, options] = loadOptions(
172
+ {
173
+ options: {
174
+ port: {
175
+ alias: 'p',
176
+ description: 'port'
177
+ },
178
+ key: {
179
+ description: 'key'
180
+ }
181
+ }
182
+ },
183
+ fakeProcess(['', '-p', '1', '--key', '1'])
184
+ )
185
+ expect(options.port).toEqual('1')
186
+ expect(options.key).toEqual('1')
187
+ })
188
+
189
+ it('throws on missing values', () => {
190
+ expect(() =>
191
+ loadOptions(
192
+ {
193
+ options: {
194
+ port: {
195
+ description: 'port'
196
+ }
197
+ }
198
+ },
199
+ fakeProcess(['', '--port'])
200
+ )
201
+ ).toThrowErrorMatchingSnapshot()
202
+ })
203
+
204
+ it('throws on unknown args', () => {
205
+ expect(() =>
206
+ loadOptions(
207
+ {
208
+ options: {
209
+ port: {
210
+ description: 'port'
211
+ }
212
+ }
213
+ },
214
+ fakeProcess(['', '--unknown', '1'])
215
+ )
216
+ ).toThrowErrorMatchingSnapshot()
217
+ })
218
+
219
+ it('throws on unparsed args', () => {
220
+ expect(() =>
221
+ loadOptions(
222
+ {
223
+ options: {
224
+ port: {
225
+ description: 'port',
226
+ parse: number
227
+ }
228
+ }
229
+ },
230
+ fakeProcess(['', '--port', 'W_W'])
231
+ )
232
+ ).toThrowErrorMatchingSnapshot()
233
+ })
234
+ })
235
+
236
+ describe('parsers', () => {
237
+ describe('oneOf', () => {
238
+ it('should return error on invalid values', () => {
239
+ let result = oneOf(['1', '2'], '3')
240
+ expect(result[0]).toMatchSnapshot()
241
+ })
242
+ it('should return null on correct values', () => {
243
+ expect(oneOf(['1', '2'], '1')).toEqual([null, '1'])
244
+ })
245
+ })
246
+
247
+ describe('number', () => {
248
+ it('should return error on invalid values', () => {
249
+ let result = number('not a number')
250
+ expect(result[0]).toMatchSnapshot()
251
+ })
252
+ it('should return null on correct values', () => {
253
+ expect(number('1')).toEqual([null, 1])
254
+ expect(number('1why parseInt is so permissive')).toEqual([null, 1])
255
+ })
256
+ })
257
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logux/server",
3
- "version": "0.10.1",
3
+ "version": "0.10.5",
4
4
  "description": "Build own Logux server or make proxy between WebSocket and HTTP backend on any language",
5
5
  "keywords": [
6
6
  "logux",
@@ -27,24 +27,24 @@
27
27
  "./package.json": "./package.json"
28
28
  },
29
29
  "dependencies": {
30
- "@logux/actions": "^0.2.0",
31
- "@logux/core": "^0.7.0",
30
+ "@logux/actions": "^0.2.1",
31
+ "@logux/core": "^0.7.2",
32
32
  "@types/node-fetch": "^2.5.10",
33
33
  "JSONStream": "^1.3.5",
34
- "colorette": "^1.2.2",
35
34
  "cookie": "^0.4.1",
36
- "dotenv": "^9.0.2",
37
- "globby": "^11.0.3",
35
+ "dotenv": "^10.0.0",
36
+ "globby": "^11.0.4",
38
37
  "ip": "^1.1.5",
39
- "nanodelay": "^2.0.0",
40
- "nanoevents": "^6.0.0",
41
- "nanoid": "^3.1.23",
38
+ "nanocolors": "^0.2.12",
39
+ "nanodelay": "^2.0.1",
40
+ "nanoevents": "^6.0.1",
41
+ "nanoid": "^3.1.28",
42
42
  "node-fetch": "^2.6.1",
43
- "pino": "^6.11.3",
43
+ "pino": "^6.13.3",
44
44
  "semver": "^7.3.5",
45
- "strip-ansi": "^7.0.0",
45
+ "strip-ansi": "^7.0.1",
46
46
  "url-pattern": "^1.0.3",
47
- "ws": "^7.4.5",
47
+ "ws": "^7.5.0",
48
48
  "yyyy-mm-dd": "^1.0.2"
49
49
  }
50
50
  }
package/server/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { join, relative } from 'path'
2
2
  import globby from 'globby'
3
- import { bgRed, black } from 'colorette'
3
+ import { bgRed, black } from 'nanocolors'
4
4
 
5
5
  import { createReporter } from '../create-reporter/index.js'
6
6
  import { BaseServer } from '../base-server/index.js'
@@ -130,7 +130,9 @@ export class Server extends BaseServer {
130
130
  }
131
131
  }
132
132
 
133
- async autoloadModules(files = ['modules/*/index.js', 'modules/*.js']) {
133
+ async autoloadModules(
134
+ files = ['modules/*/index.js', 'modules/*.js', '!**/*.{test,spec}.js']
135
+ ) {
134
136
  let matches = await globby(files, {
135
137
  cwd: this.options.root,
136
138
  absolute: true,