diff --git a/components/IscnRegisterForm.vue b/components/IscnRegisterForm.vue index 9a7c19ba..c2230a32 100644 --- a/components/IscnRegisterForm.vue +++ b/components/IscnRegisterForm.vue @@ -355,6 +355,15 @@ :placeholder="$t('IscnRegisterForm.placeholder.url')" /> + + + @@ -740,6 +750,7 @@ export enum AuthorDialogType { export default class IscnRegisterForm extends Vue { @Prop({ default: [] }) readonly fileRecords!: any[] @Prop({ default: [] }) readonly uploadArweaveList!: string[] + @Prop() readonly epubMetadata!: any | null @Prop(String) readonly ipfsHash!: string @Prop(String) readonly arweaveId!: string @@ -759,7 +770,7 @@ export default class IscnRegisterForm extends Vue { fileTypeOptions = [ 'epub', 'pdf', - 'mp3', + 'audio', 'jpg', 'png', ] @@ -784,8 +795,10 @@ export default class IscnRegisterForm extends Vue { tags: string[] = [] sameAs: string[] = [] url: string = '' + isbn: string = '' license: string = this.licenseOptions[0] customLicense: string = '' + thumbnailUrl: string = '' authorName: string = '' authorUrl: string[] = [] authorWalletAddress: string[] = [] @@ -834,6 +847,7 @@ export default class IscnRegisterForm extends Vue { currentAuthorDialogType: AuthorDialogType = AuthorDialogType.stakeholder sameAsList: any = [] + language: string = '' get ipfsHashList() { const list = [] @@ -987,6 +1001,7 @@ export default class IscnRegisterForm extends Vue { tagsString: this.tagsString, sameAs: this.formattedSameAsList, url: this.url, + isbn: this.isbn, exifInfo: this.exif.filter(file => file), license: this.formattedLicense, ipfsHash: this.ipfsHashList, @@ -1001,6 +1016,8 @@ export default class IscnRegisterForm extends Vue { likerIdsAddresses: this.likerIdsAddresses, authorDescriptions: this.authorDescriptions, contentFingerprints: this.customContentFingerprints, + inLanguage: this.language, + thumbnailUrl: this.thumbnailUrl, } } @@ -1084,6 +1101,16 @@ export default class IscnRegisterForm extends Vue { } async mounted() { + if (this.epubMetadata) { + this.name = this.epubMetadata.title; + this.description = this.extractText(this.epubMetadata.description); + this.author.name = this.epubMetadata.author; + this.language = this.epubMetadata.language + this.tags = this.epubMetadata.tags + this.thumbnailUrl = this.formatArweave(this.epubMetadata.thumbnailUrl) as string + if (this.author.name) { this.authors.push(this.author) } + } + this.uploadStatus = 'loading' // ISCN Fee needs Arweave fee to calculate await this.calculateISCNFee() @@ -1433,5 +1460,14 @@ export default class IscnRegisterForm extends Vue { this.displayImageSrc = this.fileRecords[index].fileData this.displayExifInfo = this.fileRecords[index].exifInfo } + + // eslint-disable-next-line class-methods-use-this + extractText(htmlString: string) { + if (!htmlString) return '' + const div = document.createElement('div'); + div.innerHTML = htmlString; + div.innerHTML = div.innerHTML.replace(//gi, "\n"); + return div.textContent || div.innerText; + } } diff --git a/components/IscnUploadForm.vue b/components/IscnUploadForm.vue index 7ef8fea9..2f7a831f 100644 --- a/components/IscnUploadForm.vue +++ b/components/IscnUploadForm.vue @@ -227,6 +227,7 @@ import { namespace } from 'vuex-class' import exifr from 'exifr' import Hash from 'ipfs-only-hash' import BigNumber from 'bignumber.js' +import ePub from 'epubjs'; import { OfflineSigner } from '@cosmjs/proto-signing' @@ -282,8 +283,6 @@ export default class UploadForm extends Vue { string, { transactionHash?: string, arweaveId?: string } >() - - likerId: string = '' error: string = '' shouldShowAlert = false @@ -292,6 +291,8 @@ export default class UploadForm extends Vue { signDialogError = '' balance = new BigNumber(0) + epubMetadataList: any[] = [] + get formClasses() { return [ 'flex', @@ -356,7 +357,7 @@ export default class UploadForm extends Vue { case 'MISSING_SIGNER': return this.$t('IscnRegisterForm.error.missingSigner') default: - return '' + return this.error } } @@ -442,6 +443,10 @@ export default class UploadForm extends Vue { console.error(err) } } + if (file.type === 'application/epub+zip') { + // eslint-disable-next-line no-await-in-loop + await this.processEPub({ buffer: fileBytes, file }) + } } } else { this.isSizeExceeded = true @@ -451,6 +456,109 @@ export default class UploadForm extends Vue { } } + async processEPub({ buffer, file }: { buffer: ArrayBuffer; file: File }) { + try { + const book = ePub(buffer) + await book.ready + const epubMetadata: any = {} + + // Get metadata + const { metadata } = book.packaging + if (metadata) { + epubMetadata.epubFileName = file.name + epubMetadata.title = metadata.title + epubMetadata.author = metadata.creator + epubMetadata.language = this.formatLanguage(metadata.language) + epubMetadata.description = metadata.description + } + + // Get tags + const opfFilePath = await (book.path as any).path + const opfContent = await book.archive.getText(opfFilePath) + const parser = new DOMParser() + const opfDocument = parser.parseFromString(opfContent, 'application/xml') + const dcSubjectElements = opfDocument.querySelectorAll( + 'dc\\:subject, subject', + ) + const subjects: string[] = [] + dcSubjectElements.forEach((element) => { + const subject = element.textContent + if (subject) { + subjects.push(subject) + } + }) + epubMetadata.tags = subjects + + // Get cover file + const coverUrl = await book.coverUrl() + if (coverUrl) { + const response = await fetch(coverUrl) + const blobData = await response.blob() + if (blobData) { + const coverFile = new File( + [blobData], + `${metadata.title}_cover.jpeg`, + { + type: 'image/jpeg', + }, + ) + const fileBytes = (await fileToArrayBuffer( + coverFile, + )) as unknown as ArrayBuffer + if (fileBytes) { + const [ + fileSHA256, + imageType, + ipfsHash, + // eslint-disable-next-line no-await-in-loop + ] = await Promise.all([ + digestFileSHA256(fileBytes), + readImageType(fileBytes), + Hash.of(Buffer.from(fileBytes)), + ]) + + epubMetadata.ipfsHash = ipfsHash + + const fileRecord: any = { + fileName: coverFile.name, + fileSize: coverFile.size, + fileType: coverFile.type, + fileBlob: coverFile, + ipfsHash, + fileSHA256, + isFileImage: !!imageType, + } + const reader = new FileReader() + reader.onload = (e) => { + if (!e.target) return + fileRecord.fileData = e.target.result as string + this.fileRecords.push(fileRecord) + } + reader.readAsDataURL(coverFile) + } + } + } + this.epubMetadataList.push(epubMetadata) + } catch (err) { + console.error(err) + } + } + + // eslint-disable-next-line class-methods-use-this + formatLanguage(language: string) { + let formattedLanguage = ''; + if (language) { + if (language.toLowerCase().startsWith('en')) { + formattedLanguage = 'en' + } else if (language.toLowerCase().startsWith('zh')) { + formattedLanguage = 'zh' + } else { + formattedLanguage = language + } + } + return formattedLanguage + } + onEnterURL() { if ( !( @@ -472,7 +580,13 @@ export default class UploadForm extends Vue { } handleDeleteFile(index: number) { - this.fileRecords.splice(index, 1) + const deletedFile = this.fileRecords[index]; + this.fileRecords.splice(index, 1); + + const indexToDelete = this.epubMetadataList.findIndex(item => item.ipfsHash === deletedFile.ipfsHashList); + if (indexToDelete !== -1) { + this.epubMetadataList.splice(indexToDelete, 1); + } } handleClickExifInfo(index: number) { @@ -514,6 +628,10 @@ export default class UploadForm extends Vue { } if (arweaveId) { this.sentArweaveTransactionInfo.set(ipfsHash, { transactionHash: '', arweaveId }); + const metadata = this.epubMetadataList.find((data: any) => data.ipfsHash === ipfsHash) + if (metadata) { + metadata.thumbnailUrl = arweaveId; + } } if (!this.arweaveFeeTargetAddress) { this.arweaveFeeTargetAddress = address; @@ -589,19 +707,21 @@ export default class UploadForm extends Vue { if (arweaveId) { const uploadedData = this.sentArweaveTransactionInfo.get(records.ipfsHash) || {}; this.sentArweaveTransactionInfo.set(records.ipfsHash, { ...uploadedData, arweaveId }); + if (tempRecord.fileName.includes('cover.jpeg')) { + const metadata = this.epubMetadataList.find((file: any) => file.ipfsHash === records.ipfsHash) + metadata.thumbnailUrl = arweaveId + } this.$emit('arweaveUploaded', { arweaveId }) this.isOpenSignDialog = false } else { - this.shouldShowAlert = true - this.errorMessage = this.$t('IscnRegisterForm.error.arweave') as string - this.$emit('handleContinue') + this.isOpenWarningSnackbar = true + this.error = this.$t('IscnRegisterForm.error.arweave') as string + throw new Error(this.error) } } catch (err) { // TODO: Handle error // eslint-disable-next-line no-console - console.error(err) - this.shouldShowAlert = true - this.errorMessage = (err as Error).toString() + throw new Error(err as string) } } @@ -637,12 +757,26 @@ export default class UploadForm extends Vue { } catch (error) { // eslint-disable-next-line no-console console.error(error) + this.isOpenWarningSnackbar = true + this.error = (error as Error).toString() + this.uploadStatus = ''; + return } finally { this.uploadStatus = ''; } const uploadArweaveIdList = Array.from(this.sentArweaveTransactionInfo.values()).map(entry => entry.arweaveId); - this.$emit('submit', { fileRecords: this.fileRecords, arweaveIds: uploadArweaveIdList }) + this.fileRecords.forEach((record: any, index:number) => { + if (this.sentArweaveTransactionInfo.has(record.ipfsHash)) { + const arweaveId = this.sentArweaveTransactionInfo.get( + record.ipfsHash, + )?.arweaveId + if (arweaveId) { + this.fileRecords[index].arweaveId = arweaveId + } + } + }) + this.$emit('submit', { fileRecords: this.fileRecords, arweaveIds: uploadArweaveIdList, epubMetadata: this.epubMetadataList[0] }) } handleSignDialogClose() { diff --git a/components/SameAsFieldList.vue b/components/SameAsFieldList.vue index ce882d65..73a56370 100644 --- a/components/SameAsFieldList.vue +++ b/components/SameAsFieldList.vue @@ -16,13 +16,13 @@
- + - + +
@Prop({ default: () => [] }) readonly currentList!: Array + @Prop({ default: () => [] }) readonly fileRecords!: Array @Prop(String) readonly name!: string | undefined sameAsList: any = [{ @@ -86,6 +94,11 @@ export default class WalletFieldList extends Vue { filetype: SAME_AS_FILE_TYPES[0], }] + fileTypeToFind = [ + 'epub', + 'pdf', + ] + // eslint-disable-next-line class-methods-use-this get sameAsFiletypeOptions() { return SAME_AS_FILE_TYPES @@ -101,7 +114,7 @@ export default class WalletFieldList extends Vue { return this.name.replace(/[.,!?;:'"(){}[\]<>]/g, '').replace(/\s+/g, '_').toUpperCase(); } - get formatUrlOptions() { + get filteredUrlOptions() { return this.urlOptions.filter(url => url.startsWith('ar://')) } @@ -112,20 +125,30 @@ export default class WalletFieldList extends Vue { id: `${list.url}-${list.filename}`, filename: list.filename, filetype: list.filetype || SAME_AS_FILE_TYPES[0], + originFileName: list.originFileName, })) - } else if (this.formatUrlOptions.length) { - this.sameAsList = this.formatUrlOptions.map((url, index) => ({ - url, - id: `${url}-${index}`, - filename: this.formatName, - filetype: SAME_AS_FILE_TYPES[0], - })) + } else if (this.filteredUrlOptions.length) { + this.sameAsList = this.fileRecords + .filter((file) => this.fileTypeToFind.includes(this.formatFileType(file.fileType)) && file.arweaveId) + .map((file, index) => { + const url = this.filteredUrlOptions.find((ar) => ar.includes(file.arweaveId)); + const formattedFileType = this.formatFileType(file.fileType); + + return { + url, + id: `${url}-${index}`, + filename: this.formatName, + filetype: formattedFileType || SAME_AS_FILE_TYPES[0], + originFileName: file.fileName || '', + }; + }); } else { this.sameAsList = [{ url: '', id: 1, filename: this.formatName, filetype: SAME_AS_FILE_TYPES[0], + originFileName:'', }] } } @@ -159,5 +182,35 @@ export default class WalletFieldList extends Vue { this.deleteEmptyField() this.$emit('onConfirm', this.sameAsList) } + + // eslint-disable-next-line class-methods-use-this + formatFileType(fileType: string) { + let formattedFileType = '' + if (fileType) { + switch (true) { + case fileType.includes('jpg'): + case fileType.includes('jpeg'): + formattedFileType = 'jpg' + break + case fileType.includes('png'): + formattedFileType = 'png' + break + case fileType.includes('audio'): + // audio/ogg + formattedFileType = 'audio' + break + case fileType.includes('pdf'): + formattedFileType = 'pdf' + break + case fileType.includes('epub'): + formattedFileType = 'epub' + break + default: + formattedFileType = '' + break + } + } + return formattedFileType + } } diff --git a/constant/index.ts b/constant/index.ts index a09ffea7..c62f91c9 100644 --- a/constant/index.ts +++ b/constant/index.ts @@ -62,7 +62,7 @@ export const WALLET_TYPES = [ export const SAME_AS_FILE_TYPES = [ 'epub', 'pdf', - 'mp3', + 'audio', 'jpg', 'png', ] diff --git a/locales/en.json b/locales/en.json index 39698d51..db70e273 100644 --- a/locales/en.json +++ b/locales/en.json @@ -214,12 +214,14 @@ "IscnRegisterForm.label.emptyFile": "No Content", "IscnRegisterForm.label.fingerprints": "Content Fingerprints", "IscnRegisterForm.label.iscn": "ISCN Title", + "IscnRegisterForm.label.isbn": "ISBN", "IscnRegisterForm.label.license": "License", "IscnRegisterForm.label.likerID": "LikerID", "IscnRegisterForm.label.sameAs" : "Same As URLs", "IscnRegisterForm.label.name": "Name", "IscnRegisterForm.label.fileName": "File name", "IscnRegisterForm.label.fileType": "File type", + "IscnRegisterForm.label.originFile": "origin file: {name}", "IscnRegisterForm.label.numbersProtocol": "Numbers Protocol", "IscnRegisterForm.label.numbersProtocol.details": "Register your image asset in {link}", "IscnRegisterForm.label.numbersProtocol.details.link": "Numbers Protocol", @@ -238,6 +240,7 @@ "IscnRegisterForm.placeholder.fileName": "File Name (en)", "IscnRegisterForm.placeholder.fileType": "File Type", "IscnRegisterForm.placeholder.url": "URL", + "IscnRegisterForm.placeholder.isbn": "ISBN 10/ ISBN 13", "IscnRegisterForm.placeholder.wallet": "Wallet Address", "IscnRegisterForm.quitAlertDialog.confirm": "Cancel Registration", "IscnRegisterForm.quitAlertDialog.content": "Your registration will be cancelled if you leave this page, and the paid fee cannot be refunded.", diff --git a/package.json b/package.json index 6fc46c55..0229f7a3 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "core-js": "^3.15.1", "cosmjs-types": "^0.8.0", "easyqrcodejs": "^4.4.6", + "epubjs": "^0.3.93", "exifr": "^7.1.2", "express": "^4.17.1", "fast-json-stable-stringify": "^2.1.0", diff --git a/pages/new/index.vue b/pages/new/index.vue index 7abe7099..a71427e7 100644 --- a/pages/new/index.vue +++ b/pages/new/index.vue @@ -41,6 +41,7 @@ :ipfs-hash="urlIpfsHash" :arweave-id="urlArweaveId" :upload-arweave-list=uploadArweaveList + :epub-metadata="epubMetadata" :step="step" @txBroadcasted="onISCNTxInfo" @@ -134,6 +135,7 @@ export default class NewIndexPage extends Vue { uploadFileRecords: any[] = [] urlFileRecords: any[] = [] + epubMetadata: any | null = null get shouldSkipToMintNFT(): boolean { return this.$route.query.mint === '1' @@ -189,9 +191,11 @@ export default class NewIndexPage extends Vue { onSubmitUpload({ fileRecords, arweaveIds, + epubMetadata, }: { fileRecords: any[] arweaveIds: string[] + epubMetadata: any }) { if (fileRecords && fileRecords.length) { this.uploadFileRecords = [...fileRecords] @@ -199,6 +203,9 @@ export default class NewIndexPage extends Vue { if (arweaveIds && arweaveIds.length) { this.uploadArweaveList = [...arweaveIds] } + if (epubMetadata) { + this.epubMetadata = {...epubMetadata} + } this.state = 'iscn' logTrackerEvent(this, 'ISCNCreate', 'ISCNConfirmFile', '', 1) } diff --git a/utils/cosmos/iscn/iscn.type.ts b/utils/cosmos/iscn/iscn.type.ts index d450ead7..7862b9ac 100644 --- a/utils/cosmos/iscn/iscn.type.ts +++ b/utils/cosmos/iscn/iscn.type.ts @@ -24,6 +24,9 @@ export interface ISCNRegisterPayload { stakeholders?: any[]; recordNotes?: string; memo?: string; + inLanguage?: string; + thumbnailUrl?: string; + isbn?: string; } export interface ISCNRecordWithID extends ISCNRecord { id: string; diff --git a/yarn.lock b/yarn.lock index d592e15a..59ec1d7e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4970,6 +4970,13 @@ resolved "https://registry.yarnpkg.com/@types/less/-/less-3.0.2.tgz#2761d477678c8374cb9897666871662eb1d1115e" integrity sha512-62vfe65cMSzYaWmpmhqCMMNl0khen89w57mByPi1OseGfcV/LV03fO8YVrNj7rFQsRWNJo650WWyh6m7p8vZmA== +"@types/localforage@0.0.34": + version "0.0.34" + resolved "https://registry.yarnpkg.com/@types/localforage/-/localforage-0.0.34.tgz#5e31c32dd8791ec4b9ff3ef47c9cb55b2d0d9438" + integrity sha512-tJxahnjm9dEI1X+hQSC5f2BSd/coZaqbIl1m3TCl0q9SVuC52XcXfV0XmoCU1+PmjyucuVITwoTnN8OlTbEXXA== + dependencies: + localforage "*" + "@types/lodash.chunk@^4.2.6": version "4.2.6" resolved "https://registry.yarnpkg.com/@types/lodash.chunk/-/lodash.chunk-4.2.6.tgz#9d35f05360b0298715d7f3d9efb34dd4f77e5d2a" @@ -6226,6 +6233,11 @@ "@webassemblyjs/wast-parser" "1.9.0" "@xtuc/long" "4.2.2" +"@xmldom/xmldom@^0.7.5": + version "0.7.13" + resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.13.tgz#ff34942667a4e19a9f4a0996a76814daac364cf3" + integrity sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g== + "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" @@ -8623,6 +8635,11 @@ core-js@^3.15.1: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.15.1.tgz#6c08ab88abdf56545045ccf5fd81f47f407e7f1a" integrity sha512-h8VbZYnc9pDzueiS2610IULDkpFFPunHwIpl8yRwFahAEEdSpHlTy3h3z3rKq5h11CaUdBEeRViu9AYvbxiMeg== +core-js@^3.18.3: + version "3.33.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.33.2.tgz#312bbf6996a3a517c04c99b9909cdd27138d1ceb" + integrity sha512-XeBzWI6QL3nJQiHmdzbAOiMYqjrb7hwU7A39Qhvd/POSa/t9E1AeZyEZx3fNvp/vtM8zXwhoL0FsiS0hD0pruQ== + core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -9179,6 +9196,14 @@ cyclist@^1.0.1: resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + data-urls@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" @@ -9885,6 +9910,21 @@ entities@^4.2.0, entities@^4.3.0: resolved "https://registry.yarnpkg.com/entities/-/entities-4.3.0.tgz#62915f08d67353bb4eb67e3d62641a4059aec656" integrity sha512-/iP1rZrSEJ0DTlPiX+jbzlA3eVkY/e8L8SozroF395fIqE3TYF/Nz7YOMAawta+vLmyJ/hkGNNPcSbMADCCXbg== +epubjs@^0.3.93: + version "0.3.93" + resolved "https://registry.yarnpkg.com/epubjs/-/epubjs-0.3.93.tgz#100c4597db152fc07d5246be38acca928b6b0b22" + integrity sha512-c06pNSdBxcXv3dZSbXAVLE1/pmleRhOT6mXNZo6INKmvuKpYB65MwU/lO7830czCtjIiK9i+KR+3S+p0wtljrw== + dependencies: + "@types/localforage" "0.0.34" + "@xmldom/xmldom" "^0.7.5" + core-js "^3.18.3" + event-emitter "^0.3.5" + jszip "^3.7.1" + localforage "^1.10.0" + lodash "^4.17.21" + marks-pane "^1.0.9" + path-webpack "0.0.3" + err-code@^3.0.0, err-code@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/err-code/-/err-code-3.0.1.tgz#a444c7b992705f2b120ee320b09972eef331c920" @@ -9984,11 +10024,29 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@~0.10.14: + version "0.10.62" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" + integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== + dependencies: + es6-iterator "^2.0.3" + es6-symbol "^3.1.3" + next-tick "^1.1.0" + es5-shim@^4.5.13: version "4.5.15" resolved "https://registry.yarnpkg.com/es5-shim/-/es5-shim-4.5.15.tgz#6a26869b261854a3b045273f5583c52d390217fe" integrity sha512-FYpuxEjMeDvU4rulKqFdukQyZSTpzhg4ScQHrAosrlVpR6GFyaw14f74yn2+4BugniIS0Frpg7TvwZocU4ZMTw== +es6-iterator@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + es6-promise@^4.0.3: version "4.2.8" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" @@ -10006,6 +10064,14 @@ es6-shim@^0.35.5: resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.6.tgz#d10578301a83af2de58b9eadb7c2c9945f7388a0" integrity sha512-EmTr31wppcaIAgblChZiuN/l9Y7DPyw8Xtbg7fIVngn6zMW+IEBJDJngeKC3x6wr0V/vcA2wqeFnaw1bFJbDdA== +es6-symbol@^3.1.1, es6-symbol@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + escalade@^3.0.2, escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -10344,6 +10410,14 @@ etag@^1.8.1, etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA== + dependencies: + d "1" + es5-ext "~0.10.14" + eventemitter3@^4.0.0, eventemitter3@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -10488,6 +10562,13 @@ express@^4.17.1: utils-merge "1.0.1" vary "~1.1.2" +ext@^1.1.2: + version "1.7.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" + integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== + dependencies: + type "^2.7.2" + extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -13693,6 +13774,16 @@ jstransformer@1.0.0: is-promise "^2.0.0" promise "^7.0.1" +jszip@^3.7.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" + integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + setimmediate "^1.0.5" + junk@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1" @@ -13941,6 +14032,13 @@ lie@3.1.1: dependencies: immediate "~3.0.5" +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + lilconfig@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.3.tgz#68f3005e921dafbd2a2afb48379986aa6d2579fd" @@ -14014,7 +14112,7 @@ loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4 emojis-list "^3.0.0" json5 "^1.0.1" -localforage@^1.8.1: +localforage@*, localforage@^1.10.0, localforage@^1.8.1: version "1.10.0" resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== @@ -14321,6 +14419,11 @@ markdown-to-jsx@^7.1.3: resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.1.3.tgz#f00bae66c0abe7dd2d274123f84cb6bd2a2c7c6a" integrity sha512-jtQ6VyT7rMT5tPV0g2EJakEnXLiPksnvlYtwQsVVZ611JsWGN8bQ1tVSDX4s6JllfEH6wmsYxNjTUAMrPmNA8w== +marks-pane@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/marks-pane/-/marks-pane-1.0.9.tgz#c0b5ab813384d8cd81faaeb3bbf3397dc809c1b3" + integrity sha512-Ahs4oeG90tbdPWwAJkAAoHg2lRR8lAs9mZXETNPO9hYg3AkjUJBKi1NQ4aaIQZVGrig7c/3NUV1jANl8rFTeMg== + mathml-tag-names@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" @@ -14986,6 +15089,11 @@ nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== +next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -15638,7 +15746,7 @@ p5@^1.4.0: resolved "https://registry.yarnpkg.com/p5/-/p5-1.4.0.tgz#d4d0f001c297525831861af5e017cdb5ef517a75" integrity sha512-U888W2ChcIzPhRhnv4FkNhaa4f5BDIWZfLhzvx9ZrQ5KtkZr/+o1UPIicV3yWTRy0HEG23NviHyDR3kgjaJ9wA== -pako@1.0.11, pako@~1.0.5: +pako@1.0.11, pako@~1.0.2, pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== @@ -15850,6 +15958,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +path-webpack@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/path-webpack/-/path-webpack-0.0.3.tgz#ff6dec749eec5a94605c04d5f63fc55607a03a16" + integrity sha512-AmeDxedoo5svf7aB3FYqSAKqMxys014lVKBzy1o/5vv9CtU7U4wgGWL1dA2o6MOzcD53ScN4Jmiq6VbtLz1vIQ== + pbkdf2@^3.0.16, pbkdf2@^3.0.3, pbkdf2@^3.0.9, pbkdf2@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" @@ -18601,7 +18714,7 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4: +setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= @@ -20086,6 +20199,16 @@ type-tagger@^1.0.0: resolved "https://registry.yarnpkg.com/type-tagger/-/type-tagger-1.0.0.tgz#dc6297e52e17097c1b92b42c16816a18f631e7f4" integrity sha512-FIPqqpmDgdaulCnRoKv1/d3U4xVBUrYn42QXWNP3XYmgfPUDuBUsgFOb9ntT0aIe0UsUP+lknpQ5d9Kn36RssA== +type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.7.2: + version "2.7.2" + resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" + integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== + typedarray-to-buffer@3.1.5, typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"