@nocobase/plugin-logger 0.18.0-alpha.7

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.
@@ -0,0 +1,406 @@
1
+ const { Writable, Readable, getStreamError } = require('streamx')
2
+ const FIFO = require('fast-fifo')
3
+ const b4a = require('b4a')
4
+ const headers = require('./headers')
5
+
6
+ const EMPTY = b4a.alloc(0)
7
+
8
+ class BufferList {
9
+ constructor () {
10
+ this.buffered = 0
11
+ this.shifted = 0
12
+ this.queue = new FIFO()
13
+
14
+ this._offset = 0
15
+ }
16
+
17
+ push (buffer) {
18
+ this.buffered += buffer.byteLength
19
+ this.queue.push(buffer)
20
+ }
21
+
22
+ shiftFirst (size) {
23
+ return this._buffered === 0 ? null : this._next(size)
24
+ }
25
+
26
+ shift (size) {
27
+ if (size > this.buffered) return null
28
+ if (size === 0) return EMPTY
29
+
30
+ let chunk = this._next(size)
31
+
32
+ if (size === chunk.byteLength) return chunk // likely case
33
+
34
+ const chunks = [chunk]
35
+
36
+ while ((size -= chunk.byteLength) > 0) {
37
+ chunk = this._next(size)
38
+ chunks.push(chunk)
39
+ }
40
+
41
+ return b4a.concat(chunks)
42
+ }
43
+
44
+ _next (size) {
45
+ const buf = this.queue.peek()
46
+ const rem = buf.byteLength - this._offset
47
+
48
+ if (size >= rem) {
49
+ const sub = this._offset ? buf.subarray(this._offset, buf.byteLength) : buf
50
+ this.queue.shift()
51
+ this._offset = 0
52
+ this.buffered -= rem
53
+ this.shifted += rem
54
+ return sub
55
+ }
56
+
57
+ this.buffered -= size
58
+ this.shifted += size
59
+
60
+ return buf.subarray(this._offset, (this._offset += size))
61
+ }
62
+ }
63
+
64
+ class Source extends Readable {
65
+ constructor (self, header, offset) {
66
+ super()
67
+
68
+ this.header = header
69
+ this.offset = offset
70
+
71
+ this._parent = self
72
+ }
73
+
74
+ _read (cb) {
75
+ if (this.header.size === 0) {
76
+ this.push(null)
77
+ }
78
+ if (this._parent._stream === this) {
79
+ this._parent._update()
80
+ }
81
+ cb(null)
82
+ }
83
+
84
+ _predestroy () {
85
+ this._parent.destroy(getStreamError(this))
86
+ }
87
+
88
+ _detach () {
89
+ if (this._parent._stream === this) {
90
+ this._parent._stream = null
91
+ this._parent._missing = overflow(this.header.size)
92
+ this._parent._update()
93
+ }
94
+ }
95
+
96
+ _destroy (cb) {
97
+ this._detach()
98
+ cb(null)
99
+ }
100
+ }
101
+
102
+ class Extract extends Writable {
103
+ constructor (opts) {
104
+ super(opts)
105
+
106
+ if (!opts) opts = {}
107
+
108
+ this._buffer = new BufferList()
109
+ this._offset = 0
110
+ this._header = null
111
+ this._stream = null
112
+ this._missing = 0
113
+ this._longHeader = false
114
+ this._callback = noop
115
+ this._locked = false
116
+ this._finished = false
117
+ this._pax = null
118
+ this._paxGlobal = null
119
+ this._gnuLongPath = null
120
+ this._gnuLongLinkPath = null
121
+ this._filenameEncoding = opts.filenameEncoding || 'utf-8'
122
+ this._allowUnknownFormat = !!opts.allowUnknownFormat
123
+ this._unlockBound = this._unlock.bind(this)
124
+ }
125
+
126
+ _unlock (err) {
127
+ this._locked = false
128
+
129
+ if (err) {
130
+ this.destroy(err)
131
+ this._continueWrite(err)
132
+ return
133
+ }
134
+
135
+ this._update()
136
+ }
137
+
138
+ _consumeHeader () {
139
+ if (this._locked) return false
140
+
141
+ this._offset = this._buffer.shifted
142
+
143
+ try {
144
+ this._header = headers.decode(this._buffer.shift(512), this._filenameEncoding, this._allowUnknownFormat)
145
+ } catch (err) {
146
+ this._continueWrite(err)
147
+ return false
148
+ }
149
+
150
+ if (!this._header) return true
151
+
152
+ switch (this._header.type) {
153
+ case 'gnu-long-path':
154
+ case 'gnu-long-link-path':
155
+ case 'pax-global-header':
156
+ case 'pax-header':
157
+ this._longHeader = true
158
+ this._missing = this._header.size
159
+ return true
160
+ }
161
+
162
+ this._locked = true
163
+ this._applyLongHeaders()
164
+
165
+ if (this._header.size === 0 || this._header.type === 'directory') {
166
+ this.emit('entry', this._header, this._createStream(), this._unlockBound)
167
+ return true
168
+ }
169
+
170
+ this._stream = this._createStream()
171
+ this._missing = this._header.size
172
+
173
+ this.emit('entry', this._header, this._stream, this._unlockBound)
174
+ return true
175
+ }
176
+
177
+ _applyLongHeaders () {
178
+ if (this._gnuLongPath) {
179
+ this._header.name = this._gnuLongPath
180
+ this._gnuLongPath = null
181
+ }
182
+
183
+ if (this._gnuLongLinkPath) {
184
+ this._header.linkname = this._gnuLongLinkPath
185
+ this._gnuLongLinkPath = null
186
+ }
187
+
188
+ if (this._pax) {
189
+ if (this._pax.path) this._header.name = this._pax.path
190
+ if (this._pax.linkpath) this._header.linkname = this._pax.linkpath
191
+ if (this._pax.size) this._header.size = parseInt(this._pax.size, 10)
192
+ this._header.pax = this._pax
193
+ this._pax = null
194
+ }
195
+ }
196
+
197
+ _decodeLongHeader (buf) {
198
+ switch (this._header.type) {
199
+ case 'gnu-long-path':
200
+ this._gnuLongPath = headers.decodeLongPath(buf, this._filenameEncoding)
201
+ break
202
+ case 'gnu-long-link-path':
203
+ this._gnuLongLinkPath = headers.decodeLongPath(buf, this._filenameEncoding)
204
+ break
205
+ case 'pax-global-header':
206
+ this._paxGlobal = headers.decodePax(buf)
207
+ break
208
+ case 'pax-header':
209
+ this._pax = this._paxGlobal === null
210
+ ? headers.decodePax(buf)
211
+ : Object.assign({}, this._paxGlobal, headers.decodePax(buf))
212
+ break
213
+ }
214
+ }
215
+
216
+ _consumeLongHeader () {
217
+ this._longHeader = false
218
+ this._missing = overflow(this._header.size)
219
+
220
+ const buf = this._buffer.shift(this._header.size)
221
+
222
+ try {
223
+ this._decodeLongHeader(buf)
224
+ } catch (err) {
225
+ this._continueWrite(err)
226
+ return false
227
+ }
228
+
229
+ return true
230
+ }
231
+
232
+ _consumeStream () {
233
+ const buf = this._buffer.shiftFirst(this._missing)
234
+ if (buf === null) return false
235
+
236
+ this._missing -= buf.byteLength
237
+ const drained = this._stream.push(buf)
238
+
239
+ if (this._missing === 0) {
240
+ this._stream.push(null)
241
+ if (drained) this._stream._detach()
242
+ return drained && this._locked === false
243
+ }
244
+
245
+ return drained
246
+ }
247
+
248
+ _createStream () {
249
+ return new Source(this, this._header, this._offset)
250
+ }
251
+
252
+ _update () {
253
+ while (this._buffer.buffered > 0 && !this.destroying) {
254
+ if (this._missing > 0) {
255
+ if (this._stream !== null) {
256
+ if (this._consumeStream() === false) return
257
+ continue
258
+ }
259
+
260
+ if (this._longHeader === true) {
261
+ if (this._missing > this._buffer.buffered) break
262
+ if (this._consumeLongHeader() === false) return false
263
+ continue
264
+ }
265
+
266
+ const ignore = this._buffer.shiftFirst(this._missing)
267
+ if (ignore !== null) this._missing -= ignore.byteLength
268
+ continue
269
+ }
270
+
271
+ if (this._buffer.buffered < 512) break
272
+ if (this._stream !== null || this._consumeHeader() === false) return
273
+ }
274
+
275
+ this._continueWrite(null)
276
+ }
277
+
278
+ _continueWrite (err) {
279
+ const cb = this._callback
280
+ this._callback = noop
281
+ cb(err)
282
+ }
283
+
284
+ _write (data, cb) {
285
+ this._callback = cb
286
+ this._buffer.push(data)
287
+ this._update()
288
+ }
289
+
290
+ _final (cb) {
291
+ this._finished = this._missing === 0 && this._buffer.buffered === 0
292
+ cb(this._finished ? null : new Error('Unexpected end of data'))
293
+ }
294
+
295
+ _predestroy () {
296
+ this._continueWrite(null)
297
+ }
298
+
299
+ _destroy (cb) {
300
+ if (this._stream) this._stream.destroy(getStreamError(this))
301
+ cb(null)
302
+ }
303
+
304
+ [Symbol.asyncIterator] () {
305
+ let error = null
306
+
307
+ let promiseResolve = null
308
+ let promiseReject = null
309
+
310
+ let entryStream = null
311
+ let entryCallback = null
312
+
313
+ const extract = this
314
+
315
+ this.on('entry', onentry)
316
+ this.on('error', (err) => { error = err })
317
+ this.on('close', onclose)
318
+
319
+ return {
320
+ [Symbol.asyncIterator] () {
321
+ return this
322
+ },
323
+ next () {
324
+ return new Promise(onnext)
325
+ },
326
+ return () {
327
+ return destroy(null)
328
+ },
329
+ throw (err) {
330
+ return destroy(err)
331
+ }
332
+ }
333
+
334
+ function consumeCallback (err) {
335
+ if (!entryCallback) return
336
+ const cb = entryCallback
337
+ entryCallback = null
338
+ cb(err)
339
+ }
340
+
341
+ function onnext (resolve, reject) {
342
+ if (error) {
343
+ return reject(error)
344
+ }
345
+
346
+ if (entryStream) {
347
+ resolve({ value: entryStream, done: false })
348
+ entryStream = null
349
+ return
350
+ }
351
+
352
+ promiseResolve = resolve
353
+ promiseReject = reject
354
+
355
+ consumeCallback(null)
356
+
357
+ if (extract._finished && promiseResolve) {
358
+ promiseResolve({ value: undefined, done: true })
359
+ promiseResolve = promiseReject = null
360
+ }
361
+ }
362
+
363
+ function onentry (header, stream, callback) {
364
+ entryCallback = callback
365
+ stream.on('error', noop) // no way around this due to tick sillyness
366
+
367
+ if (promiseResolve) {
368
+ promiseResolve({ value: stream, done: false })
369
+ promiseResolve = promiseReject = null
370
+ } else {
371
+ entryStream = stream
372
+ }
373
+ }
374
+
375
+ function onclose () {
376
+ consumeCallback(error)
377
+ if (!promiseResolve) return
378
+ if (error) promiseReject(error)
379
+ else promiseResolve({ value: undefined, done: true })
380
+ promiseResolve = promiseReject = null
381
+ }
382
+
383
+ function destroy (err) {
384
+ extract.destroy(err)
385
+ consumeCallback(err)
386
+ return new Promise((resolve, reject) => {
387
+ if (extract.destroyed) return resolve({ value: undefined, done: true })
388
+ extract.once('close', function () {
389
+ if (err) reject(err)
390
+ else resolve({ value: undefined, done: true })
391
+ })
392
+ })
393
+ }
394
+ }
395
+ }
396
+
397
+ module.exports = function extract (opts) {
398
+ return new Extract(opts)
399
+ }
400
+
401
+ function noop () {}
402
+
403
+ function overflow (size) {
404
+ size &= 511
405
+ return size && 512 - size
406
+ }
@@ -0,0 +1,321 @@
1
+ const b4a = require('b4a')
2
+
3
+ const ZEROS = '0000000000000000000'
4
+ const SEVENS = '7777777777777777777'
5
+ const ZERO_OFFSET = '0'.charCodeAt(0)
6
+ const USTAR_MAGIC = b4a.from([0x75, 0x73, 0x74, 0x61, 0x72, 0x00]) // ustar\x00
7
+ const USTAR_VER = b4a.from([ZERO_OFFSET, ZERO_OFFSET])
8
+ const GNU_MAGIC = b4a.from([0x75, 0x73, 0x74, 0x61, 0x72, 0x20]) // ustar\x20
9
+ const GNU_VER = b4a.from([0x20, 0x00])
10
+ const MASK = 0o7777
11
+ const MAGIC_OFFSET = 257
12
+ const VERSION_OFFSET = 263
13
+
14
+ exports.decodeLongPath = function decodeLongPath (buf, encoding) {
15
+ return decodeStr(buf, 0, buf.length, encoding)
16
+ }
17
+
18
+ exports.encodePax = function encodePax (opts) { // TODO: encode more stuff in pax
19
+ let result = ''
20
+ if (opts.name) result += addLength(' path=' + opts.name + '\n')
21
+ if (opts.linkname) result += addLength(' linkpath=' + opts.linkname + '\n')
22
+ const pax = opts.pax
23
+ if (pax) {
24
+ for (const key in pax) {
25
+ result += addLength(' ' + key + '=' + pax[key] + '\n')
26
+ }
27
+ }
28
+ return b4a.from(result)
29
+ }
30
+
31
+ exports.decodePax = function decodePax (buf) {
32
+ const result = {}
33
+
34
+ while (buf.length) {
35
+ let i = 0
36
+ while (i < buf.length && buf[i] !== 32) i++
37
+ const len = parseInt(buf.subarray(0, i).toString(), 10)
38
+ if (!len) return result
39
+
40
+ const b = b4a.toString(buf.subarray(i + 1, len - 1))
41
+ const keyIndex = b.indexOf('=')
42
+ if (keyIndex === -1) return result
43
+ result[b.slice(0, keyIndex)] = b.slice(keyIndex + 1)
44
+
45
+ buf = buf.subarray(len)
46
+ }
47
+
48
+ return result
49
+ }
50
+
51
+ exports.encode = function encode (opts) {
52
+ const buf = b4a.alloc(512)
53
+ let name = opts.name
54
+ let prefix = ''
55
+
56
+ if (opts.typeflag === 5 && name[name.length - 1] !== '/') name += '/'
57
+ if (b4a.byteLength(name) !== name.length) return null // utf-8
58
+
59
+ while (b4a.byteLength(name) > 100) {
60
+ const i = name.indexOf('/')
61
+ if (i === -1) return null
62
+ prefix += prefix ? '/' + name.slice(0, i) : name.slice(0, i)
63
+ name = name.slice(i + 1)
64
+ }
65
+
66
+ if (b4a.byteLength(name) > 100 || b4a.byteLength(prefix) > 155) return null
67
+ if (opts.linkname && b4a.byteLength(opts.linkname) > 100) return null
68
+
69
+ b4a.write(buf, name)
70
+ b4a.write(buf, encodeOct(opts.mode & MASK, 6), 100)
71
+ b4a.write(buf, encodeOct(opts.uid, 6), 108)
72
+ b4a.write(buf, encodeOct(opts.gid, 6), 116)
73
+ encodeSize(opts.size, buf, 124)
74
+ b4a.write(buf, encodeOct((opts.mtime.getTime() / 1000) | 0, 11), 136)
75
+
76
+ buf[156] = ZERO_OFFSET + toTypeflag(opts.type)
77
+
78
+ if (opts.linkname) b4a.write(buf, opts.linkname, 157)
79
+
80
+ b4a.copy(USTAR_MAGIC, buf, MAGIC_OFFSET)
81
+ b4a.copy(USTAR_VER, buf, VERSION_OFFSET)
82
+ if (opts.uname) b4a.write(buf, opts.uname, 265)
83
+ if (opts.gname) b4a.write(buf, opts.gname, 297)
84
+ b4a.write(buf, encodeOct(opts.devmajor || 0, 6), 329)
85
+ b4a.write(buf, encodeOct(opts.devminor || 0, 6), 337)
86
+
87
+ if (prefix) b4a.write(buf, prefix, 345)
88
+
89
+ b4a.write(buf, encodeOct(cksum(buf), 6), 148)
90
+
91
+ return buf
92
+ }
93
+
94
+ exports.decode = function decode (buf, filenameEncoding, allowUnknownFormat) {
95
+ let typeflag = buf[156] === 0 ? 0 : buf[156] - ZERO_OFFSET
96
+
97
+ let name = decodeStr(buf, 0, 100, filenameEncoding)
98
+ const mode = decodeOct(buf, 100, 8)
99
+ const uid = decodeOct(buf, 108, 8)
100
+ const gid = decodeOct(buf, 116, 8)
101
+ const size = decodeOct(buf, 124, 12)
102
+ const mtime = decodeOct(buf, 136, 12)
103
+ const type = toType(typeflag)
104
+ const linkname = buf[157] === 0 ? null : decodeStr(buf, 157, 100, filenameEncoding)
105
+ const uname = decodeStr(buf, 265, 32)
106
+ const gname = decodeStr(buf, 297, 32)
107
+ const devmajor = decodeOct(buf, 329, 8)
108
+ const devminor = decodeOct(buf, 337, 8)
109
+
110
+ const c = cksum(buf)
111
+
112
+ // checksum is still initial value if header was null.
113
+ if (c === 8 * 32) return null
114
+
115
+ // valid checksum
116
+ if (c !== decodeOct(buf, 148, 8)) throw new Error('Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?')
117
+
118
+ if (isUSTAR(buf)) {
119
+ // ustar (posix) format.
120
+ // prepend prefix, if present.
121
+ if (buf[345]) name = decodeStr(buf, 345, 155, filenameEncoding) + '/' + name
122
+ } else if (isGNU(buf)) {
123
+ // 'gnu'/'oldgnu' format. Similar to ustar, but has support for incremental and
124
+ // multi-volume tarballs.
125
+ } else {
126
+ if (!allowUnknownFormat) {
127
+ throw new Error('Invalid tar header: unknown format.')
128
+ }
129
+ }
130
+
131
+ // to support old tar versions that use trailing / to indicate dirs
132
+ if (typeflag === 0 && name && name[name.length - 1] === '/') typeflag = 5
133
+
134
+ return {
135
+ name,
136
+ mode,
137
+ uid,
138
+ gid,
139
+ size,
140
+ mtime: new Date(1000 * mtime),
141
+ type,
142
+ linkname,
143
+ uname,
144
+ gname,
145
+ devmajor,
146
+ devminor,
147
+ pax: null
148
+ }
149
+ }
150
+
151
+ function isUSTAR (buf) {
152
+ return b4a.equals(USTAR_MAGIC, buf.subarray(MAGIC_OFFSET, MAGIC_OFFSET + 6))
153
+ }
154
+
155
+ function isGNU (buf) {
156
+ return b4a.equals(GNU_MAGIC, buf.subarray(MAGIC_OFFSET, MAGIC_OFFSET + 6)) &&
157
+ b4a.equals(GNU_VER, buf.subarray(VERSION_OFFSET, VERSION_OFFSET + 2))
158
+ }
159
+
160
+ function clamp (index, len, defaultValue) {
161
+ if (typeof index !== 'number') return defaultValue
162
+ index = ~~index // Coerce to integer.
163
+ if (index >= len) return len
164
+ if (index >= 0) return index
165
+ index += len
166
+ if (index >= 0) return index
167
+ return 0
168
+ }
169
+
170
+ function toType (flag) {
171
+ switch (flag) {
172
+ case 0:
173
+ return 'file'
174
+ case 1:
175
+ return 'link'
176
+ case 2:
177
+ return 'symlink'
178
+ case 3:
179
+ return 'character-device'
180
+ case 4:
181
+ return 'block-device'
182
+ case 5:
183
+ return 'directory'
184
+ case 6:
185
+ return 'fifo'
186
+ case 7:
187
+ return 'contiguous-file'
188
+ case 72:
189
+ return 'pax-header'
190
+ case 55:
191
+ return 'pax-global-header'
192
+ case 27:
193
+ return 'gnu-long-link-path'
194
+ case 28:
195
+ case 30:
196
+ return 'gnu-long-path'
197
+ }
198
+
199
+ return null
200
+ }
201
+
202
+ function toTypeflag (flag) {
203
+ switch (flag) {
204
+ case 'file':
205
+ return 0
206
+ case 'link':
207
+ return 1
208
+ case 'symlink':
209
+ return 2
210
+ case 'character-device':
211
+ return 3
212
+ case 'block-device':
213
+ return 4
214
+ case 'directory':
215
+ return 5
216
+ case 'fifo':
217
+ return 6
218
+ case 'contiguous-file':
219
+ return 7
220
+ case 'pax-header':
221
+ return 72
222
+ }
223
+
224
+ return 0
225
+ }
226
+
227
+ function indexOf (block, num, offset, end) {
228
+ for (; offset < end; offset++) {
229
+ if (block[offset] === num) return offset
230
+ }
231
+ return end
232
+ }
233
+
234
+ function cksum (block) {
235
+ let sum = 8 * 32
236
+ for (let i = 0; i < 148; i++) sum += block[i]
237
+ for (let j = 156; j < 512; j++) sum += block[j]
238
+ return sum
239
+ }
240
+
241
+ function encodeOct (val, n) {
242
+ val = val.toString(8)
243
+ if (val.length > n) return SEVENS.slice(0, n) + ' '
244
+ return ZEROS.slice(0, n - val.length) + val + ' '
245
+ }
246
+
247
+ function encodeSizeBin (num, buf, off) {
248
+ buf[off] = 0x80
249
+ for (let i = 11; i > 0; i--) {
250
+ buf[off + i] = num & 0xff
251
+ num = Math.floor(num / 0x100)
252
+ }
253
+ }
254
+
255
+ function encodeSize (num, buf, off) {
256
+ if (num.toString(8).length > 11) {
257
+ encodeSizeBin(num, buf, off)
258
+ } else {
259
+ b4a.write(buf, encodeOct(num, 11), off)
260
+ }
261
+ }
262
+
263
+ /* Copied from the node-tar repo and modified to meet
264
+ * tar-stream coding standard.
265
+ *
266
+ * Source: https://github.com/npm/node-tar/blob/51b6627a1f357d2eb433e7378e5f05e83b7aa6cd/lib/header.js#L349
267
+ */
268
+ function parse256 (buf) {
269
+ // first byte MUST be either 80 or FF
270
+ // 80 for positive, FF for 2's comp
271
+ let positive
272
+ if (buf[0] === 0x80) positive = true
273
+ else if (buf[0] === 0xFF) positive = false
274
+ else return null
275
+
276
+ // build up a base-256 tuple from the least sig to the highest
277
+ const tuple = []
278
+ let i
279
+ for (i = buf.length - 1; i > 0; i--) {
280
+ const byte = buf[i]
281
+ if (positive) tuple.push(byte)
282
+ else tuple.push(0xFF - byte)
283
+ }
284
+
285
+ let sum = 0
286
+ const l = tuple.length
287
+ for (i = 0; i < l; i++) {
288
+ sum += tuple[i] * Math.pow(256, i)
289
+ }
290
+
291
+ return positive ? sum : -1 * sum
292
+ }
293
+
294
+ function decodeOct (val, offset, length) {
295
+ val = val.subarray(offset, offset + length)
296
+ offset = 0
297
+
298
+ // If prefixed with 0x80 then parse as a base-256 integer
299
+ if (val[offset] & 0x80) {
300
+ return parse256(val)
301
+ } else {
302
+ // Older versions of tar can prefix with spaces
303
+ while (offset < val.length && val[offset] === 32) offset++
304
+ const end = clamp(indexOf(val, 32, offset, val.length), val.length, val.length)
305
+ while (offset < end && val[offset] === 0) offset++
306
+ if (end === offset) return 0
307
+ return parseInt(val.subarray(offset, end).toString(), 8)
308
+ }
309
+ }
310
+
311
+ function decodeStr (val, offset, length, encoding) {
312
+ return b4a.toString(val.subarray(offset, indexOf(val, 0, offset, offset + length)), encoding)
313
+ }
314
+
315
+ function addLength (str) {
316
+ const len = b4a.byteLength(str)
317
+ let digits = Math.floor(Math.log(len) / Math.log(10)) + 1
318
+ if (len + digits >= Math.pow(10, digits)) digits++
319
+
320
+ return (len + digits) + str
321
+ }
@@ -0,0 +1,2 @@
1
+ exports.extract = require('./extract')
2
+ exports.pack = require('./pack')