@zip.js/zip.js 2.8.46 → 2.8.48

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 (50) hide show
  1. package/deno.json +1 -1
  2. package/dist/zip-core-external.js +130 -35
  3. package/dist/zip-core-external.min.js +1 -1
  4. package/dist/zip-core.js +140 -34
  5. package/dist/zip-core.min.js +1 -1
  6. package/dist/zip-fs-core-external.js +131 -36
  7. package/dist/zip-fs-core-external.min.js +1 -1
  8. package/dist/zip-fs-core.js +115 -32
  9. package/dist/zip-fs-core.min.js +1 -1
  10. package/dist/zip-fs-external.js +131 -36
  11. package/dist/zip-fs-external.min.js +1 -1
  12. package/dist/zip-fs-native.js +145 -37
  13. package/dist/zip-fs-native.min.js +1 -1
  14. package/dist/zip-fs.js +144 -36
  15. package/dist/zip-fs.min.js +1 -1
  16. package/dist/zip-legacy.js +142 -36
  17. package/dist/zip-legacy.min.js +1 -1
  18. package/dist/zip-native.js +142 -36
  19. package/dist/zip-native.min.js +1 -1
  20. package/dist/zip-web-worker-native.js +1 -1
  21. package/dist/zip-web-worker.js +1 -1
  22. package/dist/zip.js +141 -35
  23. package/dist/zip.min.js +1 -1
  24. package/index-native.cjs +145 -37
  25. package/index-native.min.js +1 -1
  26. package/index.cjs +144 -36
  27. package/index.d.cts +141 -0
  28. package/index.d.ts +141 -0
  29. package/index.min.js +1 -1
  30. package/lib/core/codec-pool.js +6 -3
  31. package/lib/core/codec-worker.js +2 -1
  32. package/lib/core/constants.js +2 -0
  33. package/lib/core/io.js +3 -23
  34. package/lib/core/options.js +4 -0
  35. package/lib/core/streams/codec-stream.js +2 -0
  36. package/lib/core/streams/common-crypto.js +2 -1
  37. package/lib/core/streams/zip-entry-stream.js +4 -2
  38. package/lib/core/util/blob-temp-stream.js +4 -2
  39. package/lib/core/util/compatible-streams.js +30 -2
  40. package/lib/core/util/opfs-temp-stream.js +8 -1
  41. package/lib/core/util/sync-access-handle-temp-stream.js +10 -2
  42. package/lib/core/web-worker-inline-native.js +1 -1
  43. package/lib/core/web-worker-inline-wasm.js +1 -1
  44. package/lib/core/zip-fs.js +3 -2
  45. package/lib/core/zip-reader.js +62 -9
  46. package/lib/core/zip-writer.js +43 -8
  47. package/lib/zip-core-base.js +2 -1
  48. package/lib/zip-core-reader.js +2 -1
  49. package/lib/zip-core-writer.js +10 -1
  50. package/package.json +2 -1
@@ -26,7 +26,7 @@
26
26
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
27
  */
28
28
 
29
- /* global Response, WritableStream, ReadableStream, TransformStream */
29
+ /* global WritableStream, ReadableStream, TransformStream */
30
30
  // deno-lint-ignore-file no-this-alias
31
31
 
32
32
  import {
@@ -43,6 +43,7 @@ import {
43
43
  DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH,
44
44
  LOCAL_FILE_HEADER_SIGNATURE,
45
45
  ARCHIVE_EXTRA_DATA_SIGNATURE,
46
+ DIGITAL_SIGNATURE_RECORD_SIGNATURE,
46
47
  CENTRAL_FILE_HEADER_SIGNATURE,
47
48
  CENTRAL_FILE_HEADER_LENGTH,
48
49
  END_OF_CENTRAL_DIR_SIGNATURE,
@@ -100,7 +101,8 @@ import {
100
101
  ERR_INVALID_PASSWORD,
101
102
  ERR_INVALID_UNCOMPRESSED_SIZE,
102
103
  ERR_INVALID_COMPRESSED_DATA,
103
- ERR_ABORT_CHECK_PASSWORD
104
+ ERR_ABORT_CHECK_PASSWORD,
105
+ ERR_WORKER_STARTUP_TIMEOUT
104
106
  } from "./codec-pool.js";
105
107
  import {
106
108
  initStream,
@@ -111,7 +113,7 @@ import {
111
113
  } from "./io.js";
112
114
  import { decodeText } from "./util/decode-text.js";
113
115
  import { getDataView } from "./util/array.js";
114
- import { toCompatibleReadable } from "./util/compatible-streams.js";
116
+ import { toCompatibleReadable, streamToBlob } from "./util/compatible-streams.js";
115
117
  import { Crc32 } from "./streams/codecs/crc32.js";
116
118
  import {
117
119
  PROPERTY_NAME_RAW_FILENAME,
@@ -149,6 +151,7 @@ import {
149
151
  OPTION_CHECK_AUTHENTICATION_CODE,
150
152
  OPTION_STRICTNESS,
151
153
  OPTION_MAX_APPENDED_DATA_SIZE,
154
+ OPTION_DECRYPT_CENTRAL_DIRECTORY,
152
155
  STRICTNESS_STRICT,
153
156
  STRICTNESS_BALANCED,
154
157
  STRICTNESS_TOLERANT,
@@ -210,7 +213,7 @@ class ZipReader {
210
213
  const { config } = zipReader;
211
214
  await initStream(reader);
212
215
  if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
213
- reader = new BlobReader(await new Response(reader.readable).blob());
216
+ reader = new BlobReader(await streamToBlob(reader.readable));
214
217
  await initStream(reader);
215
218
  }
216
219
  if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
@@ -250,6 +253,7 @@ class ZipReader {
250
253
  let startOffset;
251
254
  let zip64EndOfDirectory;
252
255
  let zip64EndOfDirectoryVersion2;
256
+ let directoryEncryptionInfo;
253
257
  const requiresZip64 = directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || filesLength == MAX_16_BITS || diskNumber == MAX_16_BITS;
254
258
  if (directoryDataOffset != MAX_32_BITS && diskNumber != MAX_16_BITS) {
255
259
  directoryDataOffset += getDiskOffset(reader, diskNumber);
@@ -280,6 +284,15 @@ class ZipReader {
280
284
  }
281
285
  zip64EndOfDirectory = true;
282
286
  zip64EndOfDirectoryVersion2 = getBigUint64(endOfDirectoryView, 4) > ZIP64_END_OF_CENTRAL_DIR_LENGTH - 12;
287
+ if (zip64EndOfDirectoryVersion2) {
288
+ const extensibleDataLength = Math.min(
289
+ Number(getBigUint64(endOfDirectoryView, 4)) - (ZIP64_END_OF_CENTRAL_DIR_LENGTH - 12),
290
+ reader.size - directoryDataOffset - ZIP64_END_OF_CENTRAL_DIR_LENGTH);
291
+ if (extensibleDataLength > 0) {
292
+ const rawExtensibleData = await readUint8Array(reader, directoryDataOffset + ZIP64_END_OF_CENTRAL_DIR_LENGTH, extensibleDataLength);
293
+ directoryEncryptionInfo = getDirectoryEncryptionInfo(rawExtensibleData);
294
+ }
295
+ }
283
296
  if (lastDiskNumber == MAX_16_BITS) {
284
297
  lastDiskNumber = getUint32(endOfDirectoryView, 16);
285
298
  } else if (checkAmbiguity && lastDiskNumber != getUint32(endOfDirectoryView, 16)) {
@@ -303,7 +316,7 @@ class ZipReader {
303
316
  directoryDataOffset = getDiskOffset(reader, diskNumber) + getBigUint64(endOfDirectoryView, 48) + prependedDataLength;
304
317
  }
305
318
  }
306
- const declaredDirectoryDataLength = directoryDataLength;
319
+ let declaredDirectoryDataLength = directoryDataLength;
307
320
  const centralDirectoryEndOffset = endOfDirectoryInfo.offset -
308
321
  (zip64EndOfDirectory ? ZIP64_END_OF_CENTRAL_DIR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH : 0);
309
322
  if (directoryDataOffset >= reader.size) {
@@ -351,6 +364,18 @@ class ZipReader {
351
364
  if (directoryDataOffset < 0 || directoryDataOffset >= reader.size) {
352
365
  throw new Error(ERR_BAD_FORMAT);
353
366
  }
367
+ zipReader.directoryOffset = directoryDataOffset;
368
+ zipReader.directoryLength = declaredDirectoryDataLength;
369
+ const decryptCentralDirectory = getOptionValue(zipReader, options, OPTION_DECRYPT_CENTRAL_DIRECTORY);
370
+ let decryptedDirectory;
371
+ if (decryptCentralDirectory && filesLength && directoryArray.length >= 4 &&
372
+ getUint32(directoryView, 0) != CENTRAL_FILE_HEADER_SIGNATURE &&
373
+ (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
374
+ directoryArray = await decryptCentralDirectory(directoryArray, directoryEncryptionInfo);
375
+ directoryView = getDataView(directoryArray);
376
+ declaredDirectoryDataLength = directoryArray.length;
377
+ decryptedDirectory = true;
378
+ }
354
379
  startOffset = directoryDataOffset;
355
380
  const filenameEncoding = getOptionValue(zipReader, options, OPTION_FILENAME_ENCODING);
356
381
  const commentEncoding = getOptionValue(zipReader, options, OPTION_COMMENT_ENCODING);
@@ -359,7 +384,7 @@ class ZipReader {
359
384
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
360
385
  const fileEntry = new ZipEntry(reader, config, zipReader.options);
361
386
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
362
- if (indexFile == 0 && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
387
+ if (indexFile == 0 && !decryptedDirectory && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
363
388
  throw new Error(ERR_ENCRYPTED_CENTRAL_DIRECTORY);
364
389
  }
365
390
  throw new Error(ERR_CENTRAL_DIRECTORY_NOT_FOUND);
@@ -457,7 +482,7 @@ class ZipReader {
457
482
  entry.arrayBuffer = async options => {
458
483
  const writer = new TransformStream();
459
484
  const [arrayBuffer] = await Promise.all([
460
- new Response(writer.readable).arrayBuffer(),
485
+ streamToBlob(writer.readable).then(blob => blob.arrayBuffer()),
461
486
  fileEntry.getData(writer, entry, zipReader.readRanges, options)]);
462
487
  return arrayBuffer;
463
488
  };
@@ -472,7 +497,15 @@ class ZipReader {
472
497
  }
473
498
  yield entry;
474
499
  }
475
- if (checkAmbiguity && offset != declaredDirectoryDataLength) {
500
+ let offsetAfterSignature = offset;
501
+ if (offset + 6 <= directoryArray.length && getUint32(directoryView, offset) == DIGITAL_SIGNATURE_RECORD_SIGNATURE) {
502
+ const signatureDataLength = getUint16(directoryView, offset + 4);
503
+ if (offset + 6 + signatureDataLength <= directoryArray.length) {
504
+ zipReader.digitalSignature = directoryArray.subarray(offset + 6, offset + 6 + signatureDataLength);
505
+ offsetAfterSignature = offset + 6 + signatureDataLength;
506
+ }
507
+ }
508
+ if (checkAmbiguity && offset != declaredDirectoryDataLength && offsetAfterSignature != declaredDirectoryDataLength) {
476
509
  throwAmbiguousArchive("trailing central directory data");
477
510
  }
478
511
  if (duplicateFilename) {
@@ -566,7 +599,8 @@ export {
566
599
  ERR_SPLIT_ZIP_FILE,
567
600
  ERR_OVERLAPPING_ENTRY,
568
601
  ERR_AMBIGUOUS_ARCHIVE,
569
- ERR_ENCRYPTED_CENTRAL_DIRECTORY
602
+ ERR_ENCRYPTED_CENTRAL_DIRECTORY,
603
+ ERR_WORKER_STARTUP_TIMEOUT
570
604
  };
571
605
 
572
606
  class ZipEntry {
@@ -768,6 +802,25 @@ function detectEncryptedCentralDirectory(directoryView) {
768
802
  return false;
769
803
  }
770
804
 
805
+ function getDirectoryEncryptionInfo(rawExtensibleData) {
806
+ const directoryEncryptionInfo = { rawExtensibleData };
807
+ if (rawExtensibleData.length >= 28) {
808
+ const extensibleDataView = getDataView(rawExtensibleData);
809
+ const hashDataLength = getUint16(extensibleDataView, 26);
810
+ Object.assign(directoryEncryptionInfo, {
811
+ compressionMethod: getUint16(extensibleDataView, 0),
812
+ compressedSize: Number(getBigUint64(extensibleDataView, 2)),
813
+ uncompressedSize: Number(getBigUint64(extensibleDataView, 10)),
814
+ encryptionAlgorithm: getUint16(extensibleDataView, 18),
815
+ bitLength: getUint16(extensibleDataView, 20),
816
+ flags: getUint16(extensibleDataView, 22),
817
+ hashAlgorithm: getUint16(extensibleDataView, 24),
818
+ hashData: rawExtensibleData.subarray(28, 28 + hashDataLength)
819
+ });
820
+ }
821
+ return directoryEncryptionInfo;
822
+ }
823
+
771
824
  function readCommonHeader(directory, dataView, offset) {
772
825
  const rawBitFlag = directory.rawBitFlag = getUint16(dataView, offset + 2);
773
826
  const encrypted = (rawBitFlag & BITFLAG_ENCRYPTED) == BITFLAG_ENCRYPTED;
@@ -88,6 +88,7 @@ import {
88
88
  SPLIT_ZIP_FILE_SIGNATURE,
89
89
  LOCAL_FILE_HEADER_SIGNATURE,
90
90
  DATA_DESCRIPTOR_RECORD_SIGNATURE,
91
+ DIGITAL_SIGNATURE_RECORD_SIGNATURE,
91
92
  CENTRAL_FILE_HEADER_SIGNATURE,
92
93
  CENTRAL_FILE_HEADER_LENGTH,
93
94
  END_OF_CENTRAL_DIR_SIGNATURE,
@@ -146,7 +147,8 @@ import { getRegisteredCodec } from "./codec-registry.js";
146
147
  import { supportsDeflate } from "./codec-worker.js";
147
148
  import {
148
149
  CODEC_DEFLATE,
149
- runWorker
150
+ runWorker,
151
+ ERR_UNSUPPORTED_CRYPTO_API
150
152
  } from "./codec-pool.js";
151
153
  import {
152
154
  initStream,
@@ -209,7 +211,8 @@ import {
209
211
  OPTION_OFFSET,
210
212
  OPTION_USDZ,
211
213
  OPTION_UNIX_EXTRA_FIELD_TYPE,
212
- OPTION_LOCAL_EXTRA_FIELD
214
+ OPTION_LOCAL_EXTRA_FIELD,
215
+ OPTION_SIGN_CENTRAL_DIRECTORY
213
216
  } from "./options.js";
214
217
 
215
218
  const ERR_DUPLICATED_NAME = "File already exists";
@@ -237,6 +240,7 @@ const ERR_INVALID_UNIX_EXTRA_FIELD_TYPE = "Invalid unixExtraFieldType (must be '
237
240
  const ERR_INVALID_UNIX_ID_SIZE = "uid/gid must be 0..65535 for unixExtraFieldType 'unix' (use 'infozip' for larger ids)";
238
241
  const ERR_INVALID_MSDOS_ATTRIBUTES = "Invalid msdosAttributesRaw (must be integer 0..255)";
239
242
  const ERR_INVALID_MSDOS_DATA = "Invalid msdosAttributes (must be an object with boolean flags)";
243
+ const ERR_INVALID_SIGNATURE_DATA = "Signature data exceeds 64KB";
240
244
 
241
245
  const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]);
242
246
  const EXTRAFIELD_OFFSET_AES_VENDOR_VERSION = 4;
@@ -515,7 +519,16 @@ export {
515
519
  ERR_UNSUPPORTED_FORMAT,
516
520
  ERR_UNDEFINED_UNCOMPRESSED_SIZE,
517
521
  ERR_UNDEFINED_READER,
518
- ERR_ZIP_NOT_EMPTY
522
+ ERR_ZIP_NOT_EMPTY,
523
+ ERR_INVALID_SIGNATURE_DATA,
524
+ ERR_INVALID_UID,
525
+ ERR_INVALID_GID,
526
+ ERR_INVALID_UNIX_MODE,
527
+ ERR_INVALID_UNIX_EXTRA_FIELD_TYPE,
528
+ ERR_INVALID_UNIX_ID_SIZE,
529
+ ERR_INVALID_MSDOS_ATTRIBUTES,
530
+ ERR_INVALID_MSDOS_DATA,
531
+ ERR_UNSUPPORTED_CRYPTO_API
519
532
  };
520
533
 
521
534
  async function addFile(zipWriter, name, reader, options) {
@@ -1614,8 +1627,9 @@ function updateLocalHeader({
1614
1627
 
1615
1628
  async function closeFile(zipWriter, comment, options) {
1616
1629
  const directoryDataLength = createDirectoryRecords(zipWriter.files);
1617
- const directoryStart = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
1618
- await writeEndOfDirectoryRecord(zipWriter, comment, options, { directoryStart, directoryDataLength });
1630
+ const { directoryStart, directoryArray } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
1631
+ const signatureLength = await writeDigitalSignatureRecord(zipWriter, directoryArray, options);
1632
+ await writeEndOfDirectoryRecord(zipWriter, comment, options, { directoryStart, directoryDataLength, signatureLength });
1619
1633
  }
1620
1634
 
1621
1635
  function createDirectoryRecords(files) {
@@ -1772,12 +1786,33 @@ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
1772
1786
  }
1773
1787
  }
1774
1788
  await writeData(writer, directoryDiskOffset ? directoryArray.slice(directoryDiskOffset) : directoryArray);
1775
- return { diskNumber: directoryStartDiskNumber, diskOffset: directoryStartDiskOffset };
1789
+ return {
1790
+ directoryStart: { diskNumber: directoryStartDiskNumber, diskOffset: directoryStartDiskOffset },
1791
+ directoryArray
1792
+ };
1793
+ }
1794
+
1795
+ async function writeDigitalSignatureRecord(zipWriter, directoryArray, options) {
1796
+ const signCentralDirectory = getOptionValue(zipWriter, options, OPTION_SIGN_CENTRAL_DIRECTORY);
1797
+ if (signCentralDirectory) {
1798
+ const signatureData = await signCentralDirectory(directoryArray);
1799
+ const signatureDataLength = getLength(signatureData);
1800
+ if (signatureDataLength > MAX_16_BITS) {
1801
+ throw new Error(ERR_INVALID_SIGNATURE_DATA);
1802
+ }
1803
+ const signatureRecord = createRecordWriter(6 + signatureDataLength);
1804
+ signatureRecord.uint32(DIGITAL_SIGNATURE_RECORD_SIGNATURE);
1805
+ signatureRecord.uint16(signatureDataLength);
1806
+ signatureRecord.bytes(signatureData);
1807
+ await writeData(zipWriter.writer, signatureRecord.array);
1808
+ return 6 + signatureDataLength;
1809
+ }
1810
+ return 0;
1776
1811
  }
1777
1812
 
1778
1813
  async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
1779
1814
  const { writer } = zipWriter;
1780
- const { directoryStart } = cdInfo;
1815
+ const { directoryStart, signatureLength } = cdInfo;
1781
1816
  let { directoryDataLength } = cdInfo;
1782
1817
  let filesLength = zipWriter.files.size;
1783
1818
  let diskNumber = directoryStart.diskNumber;
@@ -1816,7 +1851,7 @@ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
1816
1851
  endOfdirectoryRecord.uint64(directoryOffset);
1817
1852
  endOfdirectoryRecord.uint32(ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE);
1818
1853
  endOfdirectoryRecord.uint32(lastDiskNumber);
1819
- endOfdirectoryRecord.uint64(BigInt(getSegmentOffset(zipWriter, writer)) + BigInt(directoryDataLength));
1854
+ endOfdirectoryRecord.uint64(BigInt(getSegmentOffset(zipWriter, writer)) + BigInt(directoryDataLength) + BigInt(signatureLength));
1820
1855
  endOfdirectoryRecord.uint32(lastDiskNumber + 1);
1821
1856
  const supportZip64SplitFile = getOptionValue(zipWriter, options, OPTION_SUPPORT_ZIP64_SPLIT_FILE, true);
1822
1857
  if (supportZip64SplitFile) {
@@ -77,5 +77,6 @@ export {
77
77
  createBlobTempStream
78
78
  } from "./core/util/blob-temp-stream.js";
79
79
  export {
80
- createSyncAccessHandleTempStream
80
+ createSyncAccessHandleTempStream,
81
+ ERR_UNSUPPORTED_CONTEXT
81
82
  } from "./core/util/sync-access-handle-temp-stream.js";
@@ -47,5 +47,6 @@ export {
47
47
  ERR_SPLIT_ZIP_FILE,
48
48
  ERR_OVERLAPPING_ENTRY,
49
49
  ERR_AMBIGUOUS_ARCHIVE,
50
- ERR_ENCRYPTED_CENTRAL_DIRECTORY
50
+ ERR_ENCRYPTED_CENTRAL_DIRECTORY,
51
+ ERR_WORKER_STARTUP_TIMEOUT
51
52
  } from "./core/zip-reader.js";
@@ -41,5 +41,14 @@ export {
41
41
  ERR_UNSUPPORTED_FORMAT,
42
42
  ERR_UNDEFINED_UNCOMPRESSED_SIZE,
43
43
  ERR_UNDEFINED_READER,
44
- ERR_ZIP_NOT_EMPTY
44
+ ERR_ZIP_NOT_EMPTY,
45
+ ERR_INVALID_SIGNATURE_DATA,
46
+ ERR_INVALID_UID,
47
+ ERR_INVALID_GID,
48
+ ERR_INVALID_UNIX_MODE,
49
+ ERR_INVALID_UNIX_EXTRA_FIELD_TYPE,
50
+ ERR_INVALID_UNIX_ID_SIZE,
51
+ ERR_INVALID_MSDOS_ATTRIBUTES,
52
+ ERR_INVALID_MSDOS_DATA,
53
+ ERR_UNSUPPORTED_CRYPTO_API
45
54
  } from "./core/zip-writer.js";
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "A JavaScript library to zip and unzip files in the browser, Deno and Node.js",
4
4
  "author": "Gildas Lormeau",
5
5
  "license": "BSD-3-Clause",
6
- "version": "2.8.46",
6
+ "version": "2.8.48",
7
7
  "type": "module",
8
8
  "keywords": [
9
9
  "zip",
@@ -37,6 +37,7 @@
37
37
  "lint": "npx eslint . && deno lint",
38
38
  "test": "npm run test-node && npm run test-deno && npm run test-bun && npm run test-node-dist && npm run test-deno-dist && npm run test-bun-dist && npm run test-web-streams-polyfill && npm run test-types",
39
39
  "test-browsers": "npm run test-chrome && npm run test-firefox && npm run test-webkit",
40
+ "serve-tests": "http-server -p 8888 -c-1 .",
40
41
  "test-all": "npm run lint && npm run test && npm run test-browsers",
41
42
  "build": "npx rollup -c",
42
43
  "build-dev": "npx rollup -c --environment DEV",