From aa02db8da73237db9a59b547edf52f197ee8d2a2 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Fri, 30 Aug 2024 20:12:21 +0800 Subject: [PATCH 1/4] Initial prototype of the V3 manifest extension --- pkg/extension-v3/.env.demo | 3 + pkg/extension-v3/.env.firefox | 4 + pkg/extension-v3/.env.local | 3 + pkg/extension-v3/.env.production | 3 + pkg/extension-v3/.env.qa | 3 + pkg/extension-v3/package.json | 25 + pkg/extension-v3/src/background.ts | 70 + pkg/extension-v3/src/icons/icon-128.png | Bin 0 -> 14516 bytes pkg/extension-v3/src/icons/icon-16.png | Bin 0 -> 1478 bytes pkg/extension-v3/src/icons/icon-19.png | Bin 0 -> 1738 bytes pkg/extension-v3/src/icons/icon-24.png | Bin 0 -> 2181 bytes pkg/extension-v3/src/icons/icon-256.png | Bin 0 -> 29595 bytes pkg/extension-v3/src/icons/icon-32.png | Bin 0 -> 3022 bytes pkg/extension-v3/src/icons/icon-38.png | Bin 0 -> 3647 bytes pkg/extension-v3/src/icons/icon-48.png | Bin 0 -> 4712 bytes pkg/extension-v3/src/icons/icon-70.png | Bin 0 -> 4770 bytes pkg/extension-v3/src/icons/icon-96.png | Bin 0 -> 10231 bytes pkg/extension-v3/src/images/highlight.svg | 14 + pkg/extension-v3/src/images/label.svg | 12 + pkg/extension-v3/src/images/listen-hover.svg | 11 + pkg/extension-v3/src/images/listen.svg | 11 + .../src/images/pause-w-circle.svg | 3 + .../src/images/playback-speed.svg | 5 + .../src/images/playback-voice.svg | 15 + pkg/extension-v3/src/images/save.svg | 11 + pkg/extension-v3/src/manifest.json | 42 + .../src/scripts/content/content.ts | 74 + .../src/scripts/content/toolbar.ts | 322 ++++ pkg/extension-v3/src/scripts/omnivore-api.ts | 396 +++++ pkg/extension-v3/src/scripts/types.ts | 51 + pkg/extension-v3/src/scripts/utils.ts | 20 + pkg/extension-v3/src/views/toast.html | 562 +++++++ pkg/extension-v3/src/window.d.ts | 12 + pkg/extension-v3/tsconfig.json | 14 + pkg/extension-v3/webpack.config.js | 49 + pkg/extension-v3/yarn.lock | 1453 +++++++++++++++++ 36 files changed, 3188 insertions(+) create mode 100644 pkg/extension-v3/.env.demo create mode 100644 pkg/extension-v3/.env.firefox create mode 100644 pkg/extension-v3/.env.local create mode 100644 pkg/extension-v3/.env.production create mode 100644 pkg/extension-v3/.env.qa create mode 100644 pkg/extension-v3/package.json create mode 100644 pkg/extension-v3/src/background.ts create mode 100644 pkg/extension-v3/src/icons/icon-128.png create mode 100644 pkg/extension-v3/src/icons/icon-16.png create mode 100644 pkg/extension-v3/src/icons/icon-19.png create mode 100644 pkg/extension-v3/src/icons/icon-24.png create mode 100644 pkg/extension-v3/src/icons/icon-256.png create mode 100644 pkg/extension-v3/src/icons/icon-32.png create mode 100644 pkg/extension-v3/src/icons/icon-38.png create mode 100644 pkg/extension-v3/src/icons/icon-48.png create mode 100644 pkg/extension-v3/src/icons/icon-70.png create mode 100644 pkg/extension-v3/src/icons/icon-96.png create mode 100644 pkg/extension-v3/src/images/highlight.svg create mode 100644 pkg/extension-v3/src/images/label.svg create mode 100644 pkg/extension-v3/src/images/listen-hover.svg create mode 100644 pkg/extension-v3/src/images/listen.svg create mode 100644 pkg/extension-v3/src/images/pause-w-circle.svg create mode 100644 pkg/extension-v3/src/images/playback-speed.svg create mode 100644 pkg/extension-v3/src/images/playback-voice.svg create mode 100644 pkg/extension-v3/src/images/save.svg create mode 100644 pkg/extension-v3/src/manifest.json create mode 100644 pkg/extension-v3/src/scripts/content/content.ts create mode 100644 pkg/extension-v3/src/scripts/content/toolbar.ts create mode 100644 pkg/extension-v3/src/scripts/omnivore-api.ts create mode 100644 pkg/extension-v3/src/scripts/types.ts create mode 100644 pkg/extension-v3/src/scripts/utils.ts create mode 100644 pkg/extension-v3/src/views/toast.html create mode 100644 pkg/extension-v3/src/window.d.ts create mode 100644 pkg/extension-v3/tsconfig.json create mode 100644 pkg/extension-v3/webpack.config.js create mode 100644 pkg/extension-v3/yarn.lock diff --git a/pkg/extension-v3/.env.demo b/pkg/extension-v3/.env.demo new file mode 100644 index 000000000..e9a203c8f --- /dev/null +++ b/pkg/extension-v3/.env.demo @@ -0,0 +1,3 @@ +OMNIVORE_URL="https://demo.omnivore.app" +OMNIVORE_GRAPHQL_URL="https://api-demo.omnivore.app/api/graphql" +EXTENSION_NAME="Omnivore *DEMO*" \ No newline at end of file diff --git a/pkg/extension-v3/.env.firefox b/pkg/extension-v3/.env.firefox new file mode 100644 index 000000000..22ea00f92 --- /dev/null +++ b/pkg/extension-v3/.env.firefox @@ -0,0 +1,4 @@ +OMNIVORE_URL="https://omnivore.app" +OMNIVORE_GRAPHQL_URL="https://api-prod.omnivore.app/api/" +EXTENSION_NAME="Omnivore" +CONSENT_REQUIRED="true" \ No newline at end of file diff --git a/pkg/extension-v3/.env.local b/pkg/extension-v3/.env.local new file mode 100644 index 000000000..ce39d6425 --- /dev/null +++ b/pkg/extension-v3/.env.local @@ -0,0 +1,3 @@ +OMNIVORE_URL="http://localhost:3000" +OMNIVORE_GRAPHQL_URL="http://localhost:4000/api/graphql" +EXTENSION_NAME="Omnivore *local*" diff --git a/pkg/extension-v3/.env.production b/pkg/extension-v3/.env.production new file mode 100644 index 000000000..1dcd954bc --- /dev/null +++ b/pkg/extension-v3/.env.production @@ -0,0 +1,3 @@ +OMNIVORE_URL="https://omnivore.app" +OMNIVORE_GRAPHQL_URL="https://api-prod.omnivore.app/api/graphql" +EXTENSION_NAME="Omnivore" diff --git a/pkg/extension-v3/.env.qa b/pkg/extension-v3/.env.qa new file mode 100644 index 000000000..9ebaec03a --- /dev/null +++ b/pkg/extension-v3/.env.qa @@ -0,0 +1,3 @@ +OMNIVORE_URL="https://dev.omnivore.app" +OMNIVORE_GRAPHQL_URL="https://dev.omnivore.app/api/graphql" +EXTENSION_NAME="Omnivore *QA*" diff --git a/pkg/extension-v3/package.json b/pkg/extension-v3/package.json new file mode 100644 index 000000000..d6069582a --- /dev/null +++ b/pkg/extension-v3/package.json @@ -0,0 +1,25 @@ +{ + "name": "omnivore-extension", + "version": "1.0.0", + "description": "browser extension for omnivore", + "scripts": { + "build": "env EXT_ENV=local webpack --mode production", + "watch": "webpack --mode development --watch" + }, + "devDependencies": { + "@types/chrome": "^0.0.268", + "@types/dompurify": "^3.0.5", + "@types/firefox-webext-browser": "^120.0.4", + "clean-webpack-plugin": "^4.0.0", + "copy-webpack-plugin": "^12.0.2", + "dotenv-webpack": "^8.1.0", + "ts-loader": "^8.0.0", + "typescript": "^4.0.0", + "webpack": "^5.0.0", + "webpack-cli": "^4.0.0" + }, + "dependencies": { + "nanoid": "^4.0.2", + "uuid": "^8.3.2" + } +} diff --git a/pkg/extension-v3/src/background.ts b/pkg/extension-v3/src/background.ts new file mode 100644 index 000000000..52d7242e4 --- /dev/null +++ b/pkg/extension-v3/src/background.ts @@ -0,0 +1,70 @@ +import { savePageRequest } from './scripts/omnivore-api' +import { isSavePageInput } from './scripts/types' + +const browserAPI = typeof browser !== 'undefined' ? browser : chrome + +chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => { + console.log('message: ', message, 'sender', sender.tab?.id) + if (message.action === 'savePage' && isSavePageInput(message)) { + try { + const result = await savePageRequest({ + url: message.url, + title: message.title, + clientRequestId: message.clientRequestId, + originalContent: message.originalContent, + }) + if (sender.tab?.id) { + switch (result) { + case 'success': + chrome.tabs.sendMessage(sender.tab?.id, { + message: 'startToolbarDismiss', + status: 'success', + }) + break + case 'failure': + chrome.tabs.sendMessage(sender.tab?.id, { + message: 'startToolbarDismiss', + status: 'failure', + }) + break + case 'unauthorized': + chrome.tabs.sendMessage(sender.tab?.id, { + message: 'showLoggedOutToolbar', + }) + break + } + } + } catch (err) {} + } + return true +}) + +const scriptsAlreadyLoaded = async (tabId: number) => { + try { + const pingCheck = await chrome.tabs.sendMessage(tabId, { + message: 'ping', + }) + console.log('pingCheck: ', pingCheck) + return true + } catch { + return false + } +} + +browserAPI.action.onClicked.addListener(async (tab) => { + const tabId = tab.id + if (tabId) { + try { + const scriptsLoaded = await scriptsAlreadyLoaded(tabId) + if (!scriptsLoaded) { + await browserAPI.scripting.executeScript({ + target: { tabId }, + files: ['content.js'], + }) + } + } catch (err) { + console.log('[omnivore] error injecting content script: ', err) + } + chrome.tabs.sendMessage(tabId, { message: 'showToolbar' }) + } +}) diff --git a/pkg/extension-v3/src/icons/icon-128.png b/pkg/extension-v3/src/icons/icon-128.png new file mode 100644 index 0000000000000000000000000000000000000000..d6df58ae7cf218c23a86955b5be2aa6912730426 GIT binary patch literal 14516 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 literal 0 HcmV?d00001 diff --git a/pkg/extension-v3/src/icons/icon-16.png b/pkg/extension-v3/src/icons/icon-16.png new file mode 100644 index 0000000000000000000000000000000000000000..5c0b8ad309489fa4b951d73f0817f25da74d8479 GIT binary patch literal 1478 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+n z3NbJPS&Tr)z$nE4G7ZRL@M4sPvx68lplX;H7}_%#SfFa6fHVkr05M1pgl1mAh%j*h z6I`{x0%imor0saV%ts)_S>O>_%)r1c48n{Iv*t(uO^eJ7i71Ki^|4CM&(%vz$xlkv ztH>0+>{umUo3Q%e#RDspr3imfVamB1>jfNYSkzLEl1NlCV?QiN}Sf^&XRs)CuG zfu4bq9hZWFf=y9MnpKdC8&o@xXRDM^Qc_^0uU}qXu2*iXmtT~wZ)j<0sc&GUZ)Btk zRH0j3nOBlnp_^B%3^4>|j!SBBa#3bMNoIbY0?6FNr2NtnTO}osMQ{LdXGvxn!lt}p zsJDO~)CbAv8|oS8!_5Y2wE>A*`4?rT0&NDFZ)a!&R*518wZ}#uWI2*!AU*|)0=;U- zWup%dHajlKxQFZv49xDHE{-7s&3!8cI{VUU{8dp zlyIb2h{~e2nJZ@crG_b)uxK9C_^+|iUP!a^Mn6&l`9A8jA5)1P^!`aX9=5$}}L z-gNb&zoxryczyKv!>P7!>VHSaNX~cB3qG)Lq5Q;->k0o?`#mCf~V@tv{!g01!f zKgQ&&gMQP!7=t|7&-6T6(;mz0zi3(8-&vnFW*t@TaLqmPNbuar4STA*Ri8y(D3SD9 zu-CLxf1lrB{WA*HS5u$M@_e!HiK&xvZg>Cq^Q7?#e;31tSsJtV^8ZdRunZ}X+U9cm z?AK>W%X)&7#W#F>nYSk5Qs;yn8+Y=(p7-j|)IU1ME=kJV*vwMu$D+Z`7`$Yq6|>V^ zw!q6P=j#W&-*njG`{l5bJJvNin%dsDgYMLrc|I4yo?Kd&+JSI?d zn0;c`{)X(M4_@70_s8_FdaLx;viof9XD^GcWleW7{qs3{W#Z-Kq31pbvPpZN*!Q2O zbP0l+XkKb4@r{ literal 0 HcmV?d00001 diff --git a/pkg/extension-v3/src/icons/icon-19.png b/pkg/extension-v3/src/icons/icon-19.png new file mode 100644 index 0000000000000000000000000000000000000000..9c5f2a8eece2421f61a4cb05bed1e2eab3e34f3f GIT binary patch literal 1738 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S1|*9D%+3HQmUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lxRtf@J#ddWzYh$IT% zsd^Q;1t47vHWgMtW^QUpqC!P(PF}H9g{=};g%ywu64qBz04piUwpEJo4N!2-FG^J~ z(=*UBP_pAvP*AWbN=dT{a&d!d2l8x{GD=Dctn~HE%ggo3jrH=2()A53EiLs8jP#9+ zbb%^#i!1X=5-W7`ij^UTz|3(;Elw`VEGWs$&r<-Io0ybeT4JlD1hNPYAnq*5Ohed| zR}A$Q(1ZFQ8GS=N1AVyJK&>_)Q7iwV%v7MwAoJ}EZNMr~#Gv-r=z}araty?$U{Rn~ z?YM08;lXCdB^mdS9hiu`JzX3_ECfqKYJH}L%G90vU8p~u`@7bi>YW~aOEs6}O#Ixe zncZT>ljE8#u`6dr^k@0!Cw5-D9#+3$hMBvWnDh_Fo0Hb|+s{&s-t6L#**9~g#H0X) zg8fHM|E+sp?YF;JRxfJq+q>20ZvM1={?m5<^KyxQ=^Pi=CaKNfe<4?p=oC6RphbS2 zt>Cd4Kh_(3d+)2b>kY>TFU2E@%e4F(FA7$A1vV@(Wbd22;X|Iw`}jof*^mDB#51V< znX4*rs?cJSx#BDZfusq~9?TIIYs~zzl1rHL@R9?39A9mp-F-Woy@o@LN&Omk@SN0L z&zc0>bS7P4T4-rjbG!e+UWq$D%hp7_YrFpVNz}A+iJLQKbbnVky{p@@j7=qh&F4&M zrGS4uYwYR;Yrm|WJ^9ve_w$d>#XH*U-N6mmX( zPw%R&dV6;4lUuuZRTo&Rsw;kJv`bzlBhFqiG_YyQ3M!QyqRC1gJvUYZ_UW2$z@ z&o%Xw)yyoNc`5DIb&hARnQqusRG6G1b@i*R#Z}vm`|JG|?cB;fJKIj-0>iW^6@>-m znpNz_C;Ckc3DQ{|wn|`A@U_Mo*Qw7Xe|4y>YzoY|9o459FQWRiU4U!(hZtW~Ay4Of zy?b0OKeQ)F-afJQq)R6oYv4`=dCu~Ay^?J+KMFr*5|!=>43BPmb?P{W%Y%a7syd6N zq&gldHhf}LbfU|p`t~t}Mzfbazk3v&yX==p(l#P34cqzQwT(YVo?XA_HX@#dQ&-Phz zs9E31 z+yk4RM|(})bzs%=r_Yz%yA$84{66IID_{9*VYO|qw=Y}q#pmdKI;Vst00jf8 AxBvhE literal 0 HcmV?d00001 diff --git a/pkg/extension-v3/src/icons/icon-24.png b/pkg/extension-v3/src/icons/icon-24.png new file mode 100644 index 0000000000000000000000000000000000000000..a0654130ba29b356c4116ece452857aa7dab2c56 GIT binary patch literal 2181 zcmY*bdpwi-AAe@ZZ80RHG9wYTA!N2EG|X~|##~bF%srd4&FK`GkYc*Hq$DKCC1pBE zoj3`VOPy4ll50keMCCHoc~<@EcfQZ-^L*al_xJsIf4-mRuP1Y-t0O{ALk<7{gcF7A z0cCY@$Vfx)AvS3dN|NEWF17$rpCi8#C>#fm53aBMak%QnNtC4}Ql ztgNhXcvGCIsWGH5W^!X$fgIylrp`B$|M`$ZnZXH+corir7A^J-42nx+kuVr>qaW+r zJz0#fpPgcv-^YRm#EDOECRjY~hc{G86te`k1V$*-S?mv*5Wgz_!+q~V#EF~#-(|i{ z`jv%71?7miAD<1BL+u$}1pw00PGnme1(D{-h^Bd}lNN3jTAqz%rTJ3*Y%T>=)}%FL z?2rtWMQfMRN-;DgY*kMqssY!RR2cWu9`}+q>8!GfCR>?<#A9;>|f7g z!UlgKEg7v`PE43{Agm5Ng3f{(gOv`>VCWUg>KM z=id+{c@J#z#%-3K`lP&a8{2=HH`-KvL=#M@yajLkc(Q|A9)<7V16P0BCAH(>Lhc?&OY@ySKXipKF%NE-8*$ zXB2eqD3q(}MhS?5WssVx`U|a2hiS<5J1oMCJgOq$S!;2irDp%qlhYhvNBih|Ih%^_#twO5aG7BvpP!rEoV`E4 zPJLlPSh{Dt+wqfWBV(uz~+^Y+A}rn zGXtZ-e=L#t#Tmzo=IX=aRHD5oZ%q=ZCzrjuDZTZP82gsGu9qDe#YY2@B!(L=ftjtP z$_j4gvw{Bb!|r*Ai+{U=0#!XxtLNF6{^F3ytsgfq>j)5N;g*%P*H7F#$N8cK9ismv=YDUcn?J8lApQ6KfImXIB znA-u83nZSiha4aJFB+Kr(GgaZmHxJfH#Sys$g#EOvCdPP;{JZ0TM~!Am>-`S$SdpP zKRj|FaqGMBAZPvc4;ZM8n{=NHb1;&Fs-b(mqnkf=?@^pl*ld6m($7}Q#amh1T`A+% z`-GgfMhbi{=v;`boU?8ZZfSnAb8D2&?N1}BHtmt*2%a;t?)T%gf^+=rhYxJJg-0KB z`(*1Jf_0smQ8S;#cBXp@=-ZBs4P6$FFY@qBR<_rl?N49R6WiM4Iqx3tZ;@a{s_W{p z@km%#a5QpS{l)&d>`jEv?oL{1mwS|bFNhbFnY6_(JPs<{vJ<9zzb(UF)c1KDn6kI<4A+Kf@|6klU@&IwbT`kH+anCWL4kK`4WpSKhy%}POo>x2WwpON#&HuY%r!5 zRJnSpSWGo2rC&#~EHlcf7CpU*Z8hi9JzRXxy$x$kGE9B>@cvbwvdvk{mY5PS2b}?@ dGl{}UH|Jsghl(xg(7yu!IN7_BYwZFK{R`fKcW(dy literal 0 HcmV?d00001 diff --git a/pkg/extension-v3/src/icons/icon-256.png b/pkg/extension-v3/src/icons/icon-256.png new file mode 100644 index 0000000000000000000000000000000000000000..a4413ba258e995fec6fcb1565eb4bc47c746d99f GIT binary patch literal 29595 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 JPDHLkV1nKbEXe=> literal 0 HcmV?d00001 diff --git a/pkg/extension-v3/src/icons/icon-32.png b/pkg/extension-v3/src/icons/icon-32.png new file mode 100644 index 0000000000000000000000000000000000000000..2270c0762cf1da4782698060e74814ec78e7c42a GIT binary patch literal 3022 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 literal 0 HcmV?d00001 diff --git a/pkg/extension-v3/src/icons/icon-38.png b/pkg/extension-v3/src/icons/icon-38.png new file mode 100644 index 0000000000000000000000000000000000000000..1041a3f2a0b8f25187fd4e26ecdb33357216152a GIT binary patch literal 3647 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 Y8gf05dS6j<_5VaoNmH?0{$a@f03*p`8~^|S literal 0 HcmV?d00001 diff --git a/pkg/extension-v3/src/icons/icon-70.png b/pkg/extension-v3/src/icons/icon-70.png new file mode 100644 index 0000000000000000000000000000000000000000..41337352fee0a6ec00414b97a8c058e37ffc61b7 GIT binary patch literal 4770 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 VmaNE>{kr_~qNT2{R&^Z{@jq2wZA1V7 literal 0 HcmV?d00001 diff --git a/pkg/extension-v3/src/icons/icon-96.png b/pkg/extension-v3/src/icons/icon-96.png new file mode 100644 index 0000000000000000000000000000000000000000..3af64b0bef541901685467332489c0a78d5ae34a GIT binary patch literal 10231 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 literal 0 HcmV?d00001 diff --git a/pkg/extension-v3/src/images/highlight.svg b/pkg/extension-v3/src/images/highlight.svg new file mode 100644 index 000000000..e81aef802 --- /dev/null +++ b/pkg/extension-v3/src/images/highlight.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/pkg/extension-v3/src/images/label.svg b/pkg/extension-v3/src/images/label.svg new file mode 100644 index 000000000..69fca4c19 --- /dev/null +++ b/pkg/extension-v3/src/images/label.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/pkg/extension-v3/src/images/listen-hover.svg b/pkg/extension-v3/src/images/listen-hover.svg new file mode 100644 index 000000000..0a8fe4a55 --- /dev/null +++ b/pkg/extension-v3/src/images/listen-hover.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/pkg/extension-v3/src/images/listen.svg b/pkg/extension-v3/src/images/listen.svg new file mode 100644 index 000000000..f77b5bb33 --- /dev/null +++ b/pkg/extension-v3/src/images/listen.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/pkg/extension-v3/src/images/pause-w-circle.svg b/pkg/extension-v3/src/images/pause-w-circle.svg new file mode 100644 index 000000000..c8f4c1082 --- /dev/null +++ b/pkg/extension-v3/src/images/pause-w-circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/pkg/extension-v3/src/images/playback-speed.svg b/pkg/extension-v3/src/images/playback-speed.svg new file mode 100644 index 000000000..41dab8b19 --- /dev/null +++ b/pkg/extension-v3/src/images/playback-speed.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/pkg/extension-v3/src/images/playback-voice.svg b/pkg/extension-v3/src/images/playback-voice.svg new file mode 100644 index 000000000..c7b1670bd --- /dev/null +++ b/pkg/extension-v3/src/images/playback-voice.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/pkg/extension-v3/src/images/save.svg b/pkg/extension-v3/src/images/save.svg new file mode 100644 index 000000000..7deeb4d1f --- /dev/null +++ b/pkg/extension-v3/src/images/save.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/pkg/extension-v3/src/manifest.json b/pkg/extension-v3/src/manifest.json new file mode 100644 index 000000000..8c1dc6508 --- /dev/null +++ b/pkg/extension-v3/src/manifest.json @@ -0,0 +1,42 @@ +{ + "manifest_version": 3, + "name": "Omnivore", + "version": "3.0", + "description": "Save content to your Omnivore library.", + "permissions": [ + "activeTab", + "scripting", + "storage" + ], + "host_permissions": [ + "http://localhost:4000/*", + "https://api-prod.omnivore.app/api/graphql", + "https://api-demo.omnivore.app/api/graphql" + ], + "background": { + "service_worker": "background.js" + }, + "web_accessible_resources": [ + { + "resources": [ + "images/*.svg", + "views/toast.html" + ], + "matches": [ + "" + ] + } + ], + "action": { + "default_icon": { + "16": "icons/icon-16.png", + "48": "icons/icon-48.png", + "128": "icons/icon-128.png" + } + }, + "icons": { + "16": "icons/icon-16.png", + "48": "icons/icon-48.png", + "128": "icons/icon-128.png" + } +} \ No newline at end of file diff --git a/pkg/extension-v3/src/scripts/content/content.ts b/pkg/extension-v3/src/scripts/content/content.ts new file mode 100644 index 000000000..6fefab6fb --- /dev/null +++ b/pkg/extension-v3/src/scripts/content/content.ts @@ -0,0 +1,74 @@ +import { v4 as uuidv4 } from 'uuid' +import { SavePageInput, ToolbarMessage } from '../types' +import { + showLoggedOutToolbar, + showToolbar, + startToolbarDismiss, +} from './toolbar' + +const collectPageContent = async (): Promise => { + const mainContent = document.documentElement.outerHTML + console.log('[omnivore] captured mainContent') + return mainContent +} + +const sendContentToServiceWorker = async (content: string) => { + try { + await chrome.runtime.sendMessage({ action: 'savePage', data: content }) + } catch (err) { + console.log('error sending content: ', err) + } +} + +// Capture content then send it to the background script +;(async () => { + const clientRequestId = uuidv4() + console.log('[omnivore] v3 extension triggered') + + // toolbar message listener + chrome.runtime.onMessage.addListener( + async (request, sender, sendResponse) => { + console.log( + '[omnivore] content script message:', + clientRequestId, + request + ) + + switch (request.message) { + case 'showToolbar': + await showToolbar(clientRequestId) + sendResponse({ success: true }) + return + case 'showLoggedOutToolbar': + showLoggedOutToolbar() + sendResponse({ success: true }) + break + case 'startToolbarDismiss': + startToolbarDismiss(request as ToolbarMessage) + sendResponse({ success: true }) + return + default: + sendResponse({ success: false }) + return + } + } + ) + + const content = await collectPageContent() + console.log('[omnivore] collected page content: ', content) + + try { + const page: SavePageInput = { + clientRequestId, + title: document.title, + url: document.location.href, + originalContent: content, + } + await chrome.runtime.sendMessage({ + action: 'savePage', + ...page, + }) + } catch (err) { + console.log('error sending content: ', err) + } +})() diff --git a/pkg/extension-v3/src/scripts/content/toolbar.ts b/pkg/extension-v3/src/scripts/content/toolbar.ts new file mode 100644 index 000000000..aa93a48a7 --- /dev/null +++ b/pkg/extension-v3/src/scripts/content/toolbar.ts @@ -0,0 +1,322 @@ +import { ToolbarMessage, ToolbarStatus } from '../types' +import { getStorageItem } from '../utils' + +const systemIcons: { [key: string]: string } = { + waiting: '
', + success: ` + + + + `, + failure: ` + + + + + `, +} + +const createToastContainer = async (clientRequestId: string) => { + console.log('===== CREATING TOAST CONTAINER ===== ') + const file = await fetch(chrome.runtime.getURL('views/toast.html')) + const html = await file.text() + const disableAutoDismiss = await getStorageItem('disableAutoDismiss') + + const root = document.createElement('div') + root.tabIndex = 0 + root.id = 'omnivore-extension-root' + if (disableAutoDismiss) { + root.setAttribute('data-disable-auto-dismiss', 'true') + } + root.setAttribute('data-omnivore-client-request-id', clientRequestId) + root.setAttribute('data-omnivore-client-request-id', clientRequestId) + root.attachShadow({ mode: 'open' }) + root.style.opacity = '1.0' + + if (root.shadowRoot) { + root.shadowRoot.innerHTML = `` + } else { + alert('Error opening Omnivore user interface.') + return + } + + const toastEl = document.createElement('div') + toastEl.id = '#omnivore-toast' + toastEl.innerHTML = html + toastEl.tabIndex = 0 + root.shadowRoot.appendChild(toastEl) + + document.body.appendChild(root) + connectButtons(root) + // connectKeyboard(root) + + updateToolbarStatus('waiting') + + return root +} + +export const showToolbar = async (clientRequestId: string) => { + let currentToastEl = + document.querySelector('#omnivore-extension-root') ?? undefined + + const bodyEl = document.body + if (!bodyEl) return + + console.log('existing currentToastEl: ', currentToastEl) + if (!currentToastEl) { + currentToastEl = await createToastContainer(clientRequestId) + } + + ;(currentToastEl as HTMLDivElement)?.focus({ + preventScroll: true, + }) + + updateToolbarStatus('waiting') +} + +const autoDismissTime = async () => { + const strVal = (await getStorageItem('autoDismissTime')) ?? '2500' + return !Number.isNaN(Number(strVal)) ? Number(strVal) : 2500 +} + +const updateToolbarStatus = async (status: ToolbarStatus) => { + const currentToastEl = document.querySelector('#omnivore-extension-root') + const statusBox = currentToastEl?.shadowRoot?.querySelector( + '.omnivore-toast-statusBox' + ) + console.log('updating', status, statusBox) + + if (statusBox) { + switch (status) { + case 'success': + statusBox.innerHTML = systemIcons.success + break + case 'failure': + statusBox.innerHTML = systemIcons.failure + break + case 'waiting': + statusBox.innerHTML = systemIcons.waiting + break + } + } +} + +const cancelAutoDismiss = () => { + const currentToastEl = document.querySelector('#omnivore-extension-root') + if (currentToastEl) { + currentToastEl.setAttribute('data-disable-auto-dismiss', 'true') + } +} + +// If the user has not disabled auto dismiss on the toolbar this +// will remove it. If the user interacts with the toolbar, this +// dismiss will also be ignored. +export const startToolbarDismiss = async (message: ToolbarMessage) => { + if (message.status) { + updateToolbarStatus(message.status) + } + + const dimissTime = await autoDismissTime() + + setTimeout(() => { + const currentToastEl = document.querySelector('#omnivore-extension-root') + if ( + currentToastEl && + !currentToastEl.getAttribute('data-disable-auto-dismiss') + ) { + ;(currentToastEl as HTMLElement).style.transition = 'opacity 3.5s ease;' + ;(currentToastEl as HTMLElement).style.opacity = '0' + setTimeout(() => { + const currentToastEl = document.querySelector( + '#omnivore-extension-root' + ) + if ( + currentToastEl && + !currentToastEl.getAttribute('data-disable-auto-dismiss') + ) { + currentToastEl.remove() + } + }, 500) + } + }, dimissTime) +} + +const connectButtons = (root: HTMLElement) => { + const btns = [ + { id: '#omnivore-toast-add-note-btn', func: addNote }, + // { id: '#omnivore-toast-edit-title-btn', func: editTitle }, + // { id: '#omnivore-toast-edit-labels-btn', func: editLabels }, + { id: '#omnivore-toast-read-now-btn', func: readNow }, + // { id: '#omnivore-open-menu-btn', func: openMenu }, + { id: '#omnivore-toast-close-btn', func: closeToolbar }, + { id: '#omnivore-toast-login-btn', func: login }, + // { id: '#omnivore-toast-archive-btn', func: archive }, + // { id: '#omnivore-toast-delete-btn', func: deleteItem }, + ] + + for (const btnInfo of btns) { + const btn = root.shadowRoot?.querySelector(btnInfo.id) + if (btn) { + btn.addEventListener('click', btnInfo.func) + } + } + + var x = window.matchMedia('(max-width: 500px)') + if (x.matches) { + const labels = root.shadowRoot?.querySelectorAll( + '.omnivore-top-button-label' + ) + labels?.forEach((label) => { + label.style.display = 'none' + }) + const container = root.shadowRoot?.querySelector( + '#omnivore-toast-container' + ) + if (container) { + container.style.width = '280px' + container.style.top = 'unset' + container.style.bottom = '20px' + } + } +} + +export const showLoggedOutToolbar = () => { + cancelAutoDismiss() + updateToolbarStatus('failure') + toggleRow('#omnivore-logged-out-row') + disableAllButtons() + updateStatusBox( + '#omnivore-logged-out-status', + undefined, + `You are not logged in.`, + undefined + ) +} + +const updateStatusBox = ( + boxId: string, + state: ToolbarStatus | undefined, + message: string, + dismissAfter: number | undefined +) => { + const currentToastEl = document.querySelector('#omnivore-extension-root') + const statusBox = currentToastEl?.shadowRoot?.querySelector(boxId) + const image = (() => { + switch (state) { + case 'waiting': + return systemIcons.animatedLoader + case 'success': + return systemIcons.success + case 'failure': + return systemIcons.failure + default: + return undefined + } + })() + if (image && statusBox) { + statusBox.innerHTML = `${image}${message}` + } else if (statusBox) { + statusBox.innerHTML = message + } + if (dismissAfter && statusBox) { + setTimeout(() => { + statusBox.innerHTML = '' + }, dismissAfter) + } +} + +const disableAllButtons = () => { + const actionButtons = [ + '#omnivore-toast-edit-title-btn', + '#omnivore-toast-edit-labels-btn', + '#omnivore-toast-read-now-btn', + '#omnivore-toast-add-note-btn', + '#omnivore-open-menu-btn', + ] + let currentToastEl = document.querySelector('#omnivore-extension-root') + actionButtons.forEach((btnId) => { + const btn = + currentToastEl?.shadowRoot?.querySelector(btnId) + if (btn) { + btn.disabled = true + } + }) +} + +const toggleRow = (rowId: string) => { + let currentToastEl = document.querySelector('#omnivore-extension-root') + + if (!currentToastEl) { + console.log('toggleRow: no row to toggle') + // its possible this was called after closing the extension + // so just return + return + } + + const container = currentToastEl?.shadowRoot?.querySelector(rowId) + const initialState = container?.getAttribute('data-state') + const rows = currentToastEl?.shadowRoot?.querySelectorAll( + '.omnivore-toast-func-row' + ) + + rows?.forEach((r) => { + r.setAttribute('data-state', 'closed') + }) + + if (container && initialState) { + const newState = initialState === 'open' ? 'closed' : 'open' + container.setAttribute('data-state', newState) + } +} + +// +// Button functions +// + +function login() { + window.open(new URL(`/login`, process.env.OMNIVORE_URL), '_blank') + closeToolbarLater() +} + +const addNote = () => { + console.log('[omnivore] adding note') + cancelAutoDismiss() + + const currentToastEl = document.querySelector('#omnivore-extension-root') + const clientRequestId = currentToastEl?.getAttribute( + 'data-omnivore-client-request-id' + ) + console.log('client request id: ', clientRequestId) +} + +const readNow = () => { + cancelAutoDismiss() + + let currentToastEl = document.querySelector('#omnivore-extension-root') + const container = currentToastEl?.shadowRoot?.querySelector( + '#omnivore-toast-container' + ) + container?.setAttribute('data-state', 'open') + + window.open( + new URL( + `/article?url=${encodeURI(document.location.href)}`, + process.env.OMNIVORE_URL + ), + '_blank' + ) + + closeToolbarLater() +} + +const closeToolbarLater = () => { + setTimeout(() => { + closeToolbar() + }, 1000) +} +const closeToolbar = () => { + const currentToastEl = document.querySelector('#omnivore-extension-root') + if (currentToastEl) { + currentToastEl.remove() + } +} diff --git a/pkg/extension-v3/src/scripts/omnivore-api.ts b/pkg/extension-v3/src/scripts/omnivore-api.ts new file mode 100644 index 000000000..2605d3100 --- /dev/null +++ b/pkg/extension-v3/src/scripts/omnivore-api.ts @@ -0,0 +1,396 @@ +import { SavePageData } from './types' +import { getStorageItem } from './utils' + +const apiUrl = process.env.OMNIVORE_GRAPHQL_URL ?? '' + +const gqlRequest = async (query: string) => { + const apiKey = (await getStorageItem('apiKey')) as string | undefined + let headers = { + Accept: 'application/json', + 'Content-Type': 'application/json', + } as Record + if (apiKey) { + headers['Authorization'] = apiKey + } + + try { + const response = await fetch(apiUrl, { + method: 'POST', + redirect: 'follow', + credentials: 'include', + mode: 'cors', + headers, + body: query, + }) + const json = await response.json() + if (!('data' in json) || !json.data) { + throw new Error('No response data') + } + return json.data + } catch (err) { + console.log('[omnivore] error making api request: ', query) + } +} + +export type SavePageRequestResult = 'success' | 'failure' | 'unauthorized' + +export async function savePageRequest(input: { + url: string + title: string + clientRequestId: string + originalContent: string +}) { + const mutation = JSON.stringify({ + query: `mutation SavePage ($input: SavePageInput!) { + savePage(input:$input){ + ... on SaveSuccess { + url + clientRequestId + } + ... on SaveError { + errorCodes + } + } + }`, + variables: { + input: { + source: 'extension', + ...input, + }, + }, + }) + + const data = (await gqlRequest(mutation)) as SavePageData + if (data.savePage?.errorCodes?.length) { + console.log('[omnivore] api: error saving page:', data) + if (data.savePage.errorCodes.indexOf('UNAUTHORIZED') > -1) { + console.log('[omnivore] api is not authorized') + return 'unauthorized' + } + return 'failure' + } + return 'success' +} + +// async function updateLabelsCache(apiUrl, tab) { +// const query = JSON.stringify({ +// query: `query GetLabels { +// labels { +// ... on LabelsSuccess { +// labels { +// ...LabelFields +// } +// } +// ... on LabelsError { +// errorCodes +// } +// } +// } +// fragment LabelFields on Label { +// id +// name +// color +// description +// createdAt +// } +// `, +// }) + +// const data = await gqlRequest(apiUrl, query) +// if (!data.labels || data.labels['errorCodes'] || !data.labels['labels']) { +// console.log('GQL Error updating label cache response:', data, data) +// console.log(!data.labels, data.labels['errorCodes'], !data.labels['labels']) +// return [] +// } + +// await setStorage({ +// labels: data.labels.labels, +// labelsLastUpdated: new Date().toISOString(), +// }) + +// return data.labels.labels +// } + +// async function updatePageTitle(apiUrl, pageId, title) { +// const mutation = JSON.stringify({ +// query: `mutation UpdatePage($input: UpdatePageInput!) { +// updatePage(input: $input) { +// ... on UpdatePageSuccess { +// updatedPage { +// id +// } +// } +// ... on UpdatePageError { +// errorCodes +// } +// } +// } +// `, +// variables: { +// input: { +// pageId, +// title, +// }, +// }, +// }) + +// const data = await gqlRequest(apiUrl, mutation) +// if ( +// !data.updatePage || +// data.updatePage['errorCodes'] || +// !data.updatePage['updatedPage'] +// ) { +// console.log('GQL Error updating page:', data) +// throw new Error('Error updating title.') +// } +// return data.updatePage.updatePage +// } + +// async function setLabels(apiUrl, pageId, labels) { +// const mutation = JSON.stringify({ +// query: `mutation SetLabels($input: SetLabelsInput!) { +// setLabels(input: $input) { +// ... on SetLabelsSuccess { +// labels { +// id +// name +// color +// } +// } +// ... on SetLabelsError { +// errorCodes +// } +// } +// } +// `, +// variables: { +// input: { +// pageId, +// labels, +// }, +// }, +// }) + +// const data = await gqlRequest(apiUrl, mutation) +// if ( +// !data.setLabels || +// data.setLabels['errorCodes'] || +// !data.setLabels['labels'] +// ) { +// console.log('GQL Error setting labels:', data) +// throw new Error('Error setting labels.') +// } + +// await appendLabelsToCache(data.setLabels.labels) + +// return data.setLabels.labels +// } + +// async function appendLabelsToCache(labels) { +// const cachedLabels = await getStorageItem('labels') +// if (cachedLabels) { +// labels.forEach((l) => { +// const existing = cachedLabels.find((cached) => cached.name === l.name) +// if (!existing) { +// cachedLabels.unshift(l) +// } +// }) + +// await setStorage({ +// labels: cachedLabels, +// labelsLastUpdated: new Date().toISOString(), +// }) +// } else { +// await setStorage({ +// labels: labels, +// labelsLastUpdated: new Date().toISOString(), +// }) +// } +// } + +// async function addNote(apiUrl, pageId, noteId, shortId, note) { +// const query = JSON.stringify({ +// query: `query GetArticle( +// $username: String! +// $slug: String! +// $includeFriendsHighlights: Boolean +// ) { +// article(username: $username, slug: $slug) { +// ... on ArticleSuccess { +// article { +// highlights(input: { includeFriends: $includeFriendsHighlights }) { +// ...HighlightFields +// } +// } +// } +// ... on ArticleError { +// errorCodes +// } +// } +// } +// fragment HighlightFields on Highlight { +// id +// type +// annotation +// } +// `, +// variables: { +// username: 'me', +// slug: pageId, +// includeFriendsHighlights: false, +// }, +// }) + +// const data = await gqlRequest(apiUrl, query) +// if (!data.article || data.article['errorCodes'] || !data.article['article']) { +// console.log('GQL Error getting existing highlights:', data) +// return +// } + +// const existingNote = data.article.article.highlights.find( +// (h) => h.type == 'NOTE' +// ) + +// if (existingNote) { +// const mutation = JSON.stringify({ +// query: ` +// mutation UpdateHighlight($input: UpdateHighlightInput!) { +// updateHighlight(input: $input) { +// ... on UpdateHighlightSuccess { +// highlight { +// id +// } +// } +// ... on UpdateHighlightError { +// errorCodes +// } +// } +// } +// `, +// variables: { +// input: { +// highlightId: existingNote.id, +// annotation: existingNote.annotation +// ? existingNote.annotation + '\n\n' + note +// : note, +// }, +// }, +// }) +// const result = await gqlRequest(apiUrl, mutation) +// if ( +// !result.updateHighlight || +// result.updateHighlight['errorCodes'] || +// !result.updateHighlight.highlight +// ) { +// console.log('GQL Error updating note:', result) +// return +// } +// return result.updateHighlight.highlight.id +// } else { +// const mutation = JSON.stringify({ +// query: ` +// mutation CreateHighlight($input: CreateHighlightInput!) { +// createHighlight(input: $input) { +// ... on CreateHighlightSuccess { +// highlight { +// id +// } +// } +// ... on CreateHighlightError { +// errorCodes +// } +// } +// } +// `, +// variables: { +// input: { +// id: noteId, +// shortId: shortId, +// type: 'NOTE', +// articleId: pageId, +// annotation: note, +// }, +// }, +// }) +// const result = await gqlRequest(apiUrl, mutation) +// if ( +// !result.createHighlight || +// result.createHighlight['errorCodes'] || +// !result.createHighlight.highlight +// ) { +// console.log('GQL Error setting note:', result) +// return +// } +// return result.createHighlight.highlight.id +// } +// } + +// async function archive(apiUrl, pageId) { +// const mutation = JSON.stringify({ +// query: `mutation SetLinkArchived($input: ArchiveLinkInput!) { +// setLinkArchived(input: $input) { +// ... on ArchiveLinkSuccess { +// linkId +// message +// } +// ... on ArchiveLinkError { +// message +// errorCodes +// } +// } +// } +// `, +// variables: { +// input: { +// linkId: pageId, +// archived: true, +// }, +// }, +// }) + +// const data = await gqlRequest(apiUrl, mutation) +// if ( +// !data.setLinkArchived || +// data.setLinkArchived['errorCodes'] || +// !data.setLinkArchived.linkId +// ) { +// console.log('GQL Error archiving:', data) +// throw new Error('Error archiving.') +// } +// return data.setLinkArchived.linkId +// } + +// async function deleteItem(apiUrl, pageId) { +// const mutation = JSON.stringify({ +// query: `mutation SetBookmarkArticle($input: SetBookmarkArticleInput!) { +// setBookmarkArticle(input: $input) { +// ... on SetBookmarkArticleSuccess { +// bookmarkedArticle { +// id +// } +// } +// ... on SetBookmarkArticleError { +// errorCodes +// } +// } +// } +// `, +// variables: { +// input: { +// articleID: pageId, +// bookmark: false, +// }, +// }, +// }) + +// const data = await gqlRequest(apiUrl, mutation) +// if ( +// !data.setBookmarkArticle || +// data.setBookmarkArticle['errorCodes'] || +// !data.setBookmarkArticle.bookmarkedArticle +// ) { +// console.log('GQL Error deleting:', data) +// throw new Error('Error deleting.') +// } +// return data.setBookmarkArticle.bookmarkedArticle +// } diff --git a/pkg/extension-v3/src/scripts/types.ts b/pkg/extension-v3/src/scripts/types.ts new file mode 100644 index 000000000..0ddee0571 --- /dev/null +++ b/pkg/extension-v3/src/scripts/types.ts @@ -0,0 +1,51 @@ +export type ToolbarStatus = 'waiting' | 'success' | 'failure' + +export interface ToolbarMessage { + status?: ToolbarStatus +} + +export interface SavePageData { + savePage?: SavePageResult +} + +export interface SavePageResult { + url?: string + clientRequestId?: string + errorCodes?: string[] +} + +export interface SavePageInput { + url: string + title: string + clientRequestId: string + originalContent: string +} + +export function isSavePageResult(obj: any): obj is SavePageResult { + return ( + typeof obj === 'object' && + (obj.url === undefined || typeof obj.url === 'string') && + (obj.clientRequestId === undefined || + typeof obj.clientRequestId === 'string') && + (obj.errorCodes === undefined || + (Array.isArray(obj.errorCodes) && + obj.errorCodes.every((code: any) => typeof code === 'string'))) + ) +} + +export function isSavePageData(obj: any): obj is SavePageData { + return ( + typeof obj === 'object' && + (obj.savePage === undefined || isSavePageResult(obj.savePage)) + ) +} + +export function isSavePageInput(obj: any): obj is SavePageInput { + return ( + typeof obj === 'object' && + typeof obj.url === 'string' && + typeof obj.title === 'string' && + typeof obj.clientRequestId === 'string' && + typeof obj.originalContent === 'string' + ) +} diff --git a/pkg/extension-v3/src/scripts/utils.ts b/pkg/extension-v3/src/scripts/utils.ts new file mode 100644 index 000000000..cbb373c2e --- /dev/null +++ b/pkg/extension-v3/src/scripts/utils.ts @@ -0,0 +1,20 @@ +export const getStorageItem = async (singleKey: string) => { + return new Promise((resolve) => { + chrome.storage.local.get(singleKey, (result) => { + const finalResult = (result && result[singleKey]) || null + resolve(finalResult) + }) + }) +} + +// const setStorage(itemsToSet) { +// return new Promise((resolve) => { +// browserApi.storage.local.set(itemsToSet, resolve) +// }) +// } + +// function removeStorage(itemsToRemove) { +// return new Promise((resolve) => { +// browserApi.storage.local.remove(itemsToRemove, resolve) +// }) +// } diff --git a/pkg/extension-v3/src/views/toast.html b/pkg/extension-v3/src/views/toast.html new file mode 100644 index 000000000..fd32fba45 --- /dev/null +++ b/pkg/extension-v3/src/views/toast.html @@ -0,0 +1,562 @@ + + +
+
+ +
+
+ + + + + + + + + + + + + + + + +
+ +
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
    +
  • + +
  • +
+
+ +
+
+
+ +
+ + + + + + +
+ + +
\ No newline at end of file diff --git a/pkg/extension-v3/src/window.d.ts b/pkg/extension-v3/src/window.d.ts new file mode 100644 index 000000000..fd9b32bc6 --- /dev/null +++ b/pkg/extension-v3/src/window.d.ts @@ -0,0 +1,12 @@ +export {} + +declare type AndroidWebKitMessenger = { + // 1st argument is an actionID value, 2nd is jsonString + handleIdentifiableMessage: (string, string) => void +} + +declare global { + interface Window { + showToolbar?: (payload: { type: string }) => void + } +} diff --git a/pkg/extension-v3/tsconfig.json b/pkg/extension-v3/tsconfig.json new file mode 100644 index 000000000..43cf0df7e --- /dev/null +++ b/pkg/extension-v3/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "outDir": "./dist", + "module": "esnext", + "target": "es6", + "lib": ["dom", "es6"], + "moduleResolution": "node", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src/**/*"] +} \ No newline at end of file diff --git a/pkg/extension-v3/webpack.config.js b/pkg/extension-v3/webpack.config.js new file mode 100644 index 000000000..8e135d0e0 --- /dev/null +++ b/pkg/extension-v3/webpack.config.js @@ -0,0 +1,49 @@ +const path = require('path') +const DotenvPlugin = require('dotenv-webpack') +const CopyWebpackPlugin = require('copy-webpack-plugin') +const { CleanWebpackPlugin } = require('clean-webpack-plugin') + +const env = process.env.EXT_ENV || 'demo' +const dotenvPath = __dirname + '/.env.' + env + +module.exports = { + mode: /* process.env.EXT_ENV === 'production' ? 'production' : */ 'development', + devtool: + /* process.env.EXT_ENV === 'production' ? undefined : */ 'source-map', + entry: { + background: './src/background.ts', + toolbar: './src/scripts/content/toolbar.ts', + content: './src/scripts/content/content.ts', + }, + module: { + rules: [ + { + test: /\.ts$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + ], + }, + resolve: { + extensions: ['.ts', '.js'], + }, + output: { + filename: '[name].js', + path: path.resolve(__dirname, 'dist'), + }, + plugins: [ + new CleanWebpackPlugin(), + new DotenvPlugin({ + path: dotenvPath, + }), + new CopyWebpackPlugin({ + patterns: [ + { from: 'src/manifest.json', to: 'manifest.json' }, + { from: 'src/styles.css', to: 'styles.css' }, + { from: 'src/icons', to: 'icons' }, + { from: 'src/images', to: 'images' }, + { from: 'src/views', to: 'views' }, + ], + }), + ], +} diff --git a/pkg/extension-v3/yarn.lock b/pkg/extension-v3/yarn.lock new file mode 100644 index 000000000..29d6b24c5 --- /dev/null +++ b/pkg/extension-v3/yarn.lock @@ -0,0 +1,1453 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@discoveryjs/json-ext@^0.5.0": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/source-map@^0.3.3": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@sindresorhus/merge-streams@^2.1.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz#719df7fb41766bc143369eaa0dd56d8dc87c9958" + integrity sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg== + +"@types/chrome@^0.0.268": + version "0.0.268" + resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.268.tgz#d5855546f30c83e181cadd77127a162c25b480d2" + integrity sha512-7N1QH9buudSJ7sI8Pe4mBHJr5oZ48s0hcanI9w3wgijAlv1OZNUZve9JR4x42dn5lJ5Sm87V1JNfnoh10EnQlA== + dependencies: + "@types/filesystem" "*" + "@types/har-format" "*" + +"@types/dompurify@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-3.0.5.tgz#02069a2fcb89a163bacf1a788f73cb415dd75cb7" + integrity sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg== + dependencies: + "@types/trusted-types" "*" + +"@types/eslint-scope@^3.7.3": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" + integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "9.6.0" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-9.6.0.tgz#51d4fe4d0316da9e9f2c80884f2c20ed5fb022ff" + integrity sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + +"@types/filesystem@*": + version "0.0.36" + resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.36.tgz#7227c2d76bfed1b21819db310816c7821d303857" + integrity sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA== + dependencies: + "@types/filewriter" "*" + +"@types/filewriter@*": + version "0.0.33" + resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.33.tgz#d9d611db9d9cd99ae4e458de420eeb64ad604ea8" + integrity sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g== + +"@types/firefox-webext-browser@^120.0.4": + version "120.0.4" + resolved "https://registry.yarnpkg.com/@types/firefox-webext-browser/-/firefox-webext-browser-120.0.4.tgz#27eead781051b2e681a344dd2983735faadd4343" + integrity sha512-lBrpf08xhiZBigrtdQfUaqX1UauwZ+skbFiL8u2Tdra/rklkKadYmIzTwkNZSWtuZ7OKpFqbE2HHfDoFqvZf6w== + +"@types/glob@^7.1.1": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/har-format@*": + version "1.2.15" + resolved "https://registry.yarnpkg.com/@types/har-format/-/har-format-1.2.15.tgz#f352493638c2f89d706438a19a9eb300b493b506" + integrity sha512-RpQH4rXLuvTXKR0zqHq3go0RVXYv/YVqv4TnPH95VbwUxZdQlK1EtcMvQvMpDngHbt13Csh9Z4qT9AbkiQH5BA== + +"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/minimatch@*": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== + +"@types/node@*": + version "22.4.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.4.1.tgz#9b595d292c65b94c20923159e2ce947731b6fdce" + integrity sha512-1tbpb9325+gPnKK0dMm+/LMriX0vKxf6RnB0SZUqfyVkQ4fMgUSySqhxE/y8Jvs4NyF1yHzTfG9KlnkIODxPKg== + dependencies: + undici-types "~6.19.2" + +"@types/trusted-types@*": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" + integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== + +"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" + integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== + +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== + +"@webassemblyjs/helper-buffer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" + integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== + +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== + +"@webassemblyjs/helper-wasm-section@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" + integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.12.1" + +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" + integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-opt" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + "@webassemblyjs/wast-printer" "1.12.1" + +"@webassemblyjs/wasm-gen@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" + integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" + integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + +"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" + integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" + integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.2.0.tgz#7b20ce1c12533912c3b217ea68262365fa29a6f5" + integrity sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg== + +"@webpack-cli/info@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.5.0.tgz#6c78c13c5874852d6e2dd17f08a41f3fe4c261b1" + integrity sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ== + dependencies: + envinfo "^7.7.3" + +"@webpack-cli/serve@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.7.0.tgz#e1993689ac42d2b16e9194376cfb6753f6254db1" + integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== + +acorn@^8.7.1, acorn@^8.8.2: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv-keywords@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0, ajv@^8.9.0: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng== + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.21.10: + version "4.23.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" + integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== + dependencies: + caniuse-lite "^1.0.30001646" + electron-to-chromium "^1.5.4" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +caniuse-lite@^1.0.30001646: + version "1.0.30001651" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz#52de59529e8b02b1aedcaaf5c05d9e23c0c28138" + integrity sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg== + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chrome-trace-event@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b" + integrity sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ== + +clean-webpack-plugin@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz#72947d4403d452f38ed61a9ff0ada8122aacd729" + integrity sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w== + dependencies: + del "^4.1.1" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.14: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +copy-webpack-plugin@^12.0.2: + version "12.0.2" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz#935e57b8e6183c82f95bd937df658a59f6a2da28" + integrity sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA== + dependencies: + fast-glob "^3.3.2" + glob-parent "^6.0.1" + globby "^14.0.0" + normalize-path "^3.0.0" + schema-utils "^4.2.0" + serialize-javascript "^6.0.2" + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +del@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" + integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== + dependencies: + "@types/glob" "^7.1.1" + globby "^6.1.0" + is-path-cwd "^2.0.0" + is-path-in-cwd "^2.0.0" + p-map "^2.0.0" + pify "^4.0.1" + rimraf "^2.6.3" + +dotenv-defaults@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz#6b3ec2e4319aafb70940abda72d3856770ee77ac" + integrity sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg== + dependencies: + dotenv "^8.2.0" + +dotenv-webpack@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/dotenv-webpack/-/dotenv-webpack-8.1.0.tgz#4d66abc4a30395b46a030ebcd125320232b54873" + integrity sha512-owK1JcsPkIobeqjVrk6h7jPED/W6ZpdFsMPR+5ursB7/SdgDyO+VzAU+szK8C8u3qUhtENyYnj8eyXMR5kkGag== + dependencies: + dotenv-defaults "^2.0.2" + +dotenv@^8.2.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== + +electron-to-chromium@^1.5.4: + version "1.5.11" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.11.tgz#258077f1077a1c72f2925cd5b326c470a7f5adef" + integrity sha512-R1CccCDYqndR25CaXFd6hp/u9RaaMcftMkphmvuepXr5b1vfLkRml6aWVeBhXJ7rbevHkKEMJtz8XqPf7ffmew== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +enhanced-resolve@^4.0.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" + integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.5.0" + tapable "^1.0.0" + +enhanced-resolve@^5.17.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +envinfo@^7.7.3: + version "7.13.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.13.0.tgz#81fbb81e5da35d74e814941aeab7c325a606fb31" + integrity sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q== + +errno@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + +es-module-lexer@^1.2.1: + version "1.5.4" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" + integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== + +escalade@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-uri@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" + integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== + +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@^7.0.3, glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globby@^14.0.0: + version "14.0.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-14.0.2.tgz#06554a54ccfe9264e5a9ff8eded46aa1e306482f" + integrity sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw== + dependencies: + "@sindresorhus/merge-streams" "^2.1.0" + fast-glob "^3.3.2" + ignore "^5.2.4" + path-type "^5.0.0" + slash "^5.1.0" + unicorn-magic "^0.1.0" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw== + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.2.11, graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +ignore@^5.2.4: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +import-local@^3.0.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +interpret@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" + integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== + +is-core-module@^2.13.0: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" + integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== + dependencies: + hasown "^2.0.2" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-cwd@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-in-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" + integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== + dependencies: + is-path-inside "^2.1.0" + +is-path-inside@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" + integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== + dependencies: + path-is-inside "^1.0.2" + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json5@^2.1.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +loader-utils@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" + integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +memory-fs@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" + integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.0, micromatch@^4.0.4: + version "4.0.7" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" + integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.27: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +nanoid@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-4.0.2.tgz#140b3c5003959adbebf521c170f282c5e7f9fb9e" + integrity sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-5.0.0.tgz#14b01ed7aea7ddf9c7c3f46181d4d04f9c785bb8" + integrity sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg== + +picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw== + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +readable-stream@^2.0.1: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +rechoir@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" + integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg== + dependencies: + resolve "^1.9.0" + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.9.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +schema-utils@^3.1.1, schema-utils@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.2.0.tgz#70d7c93e153a273a805801882ebd3bff20d89c8b" + integrity sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.9.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.1.0" + +semver@^7.3.4: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +serialize-javascript@^6.0.1, serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +slash@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-5.1.0.tgz#be3adddcdf09ac38eebe8dcdc7b1a57a75b095ce" + integrity sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg== + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tapable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.3.10: + version "5.3.10" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199" + integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.20" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.1" + terser "^5.26.0" + +terser@^5.26.0: + version "5.31.6" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.6.tgz#c63858a0f0703988d0266a82fcbf2d7ba76422b1" + integrity sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-loader@^8.0.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.4.0.tgz#e845ea0f38d140bdc3d7d60293ca18d12ff2720f" + integrity sha512-6nFY3IZ2//mrPc+ImY3hNWx1vCHyEhl6V+wLmL4CZcm6g1CqX7UKrkc6y0i4FwcfOhxyMPCfaEvh20f4r9GNpw== + dependencies: + chalk "^4.1.0" + enhanced-resolve "^4.0.0" + loader-utils "^2.0.0" + micromatch "^4.0.0" + semver "^7.3.4" + +typescript@^4.0.0: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +unicorn-magic@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.1.0.tgz#1bb9a51c823aaf9d73a8bfcd3d1a23dde94b0ce4" + integrity sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ== + +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== + dependencies: + escalade "^3.1.2" + picocolors "^1.0.1" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +watchpack@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.2.tgz#2feeaed67412e7c33184e5a79ca738fbd38564da" + integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +webpack-cli@^4.0.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31" + integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^1.2.0" + "@webpack-cli/info" "^1.5.0" + "@webpack-cli/serve" "^1.7.0" + colorette "^2.0.14" + commander "^7.0.0" + cross-spawn "^7.0.3" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^2.2.0" + rechoir "^0.7.0" + webpack-merge "^5.7.3" + +webpack-merge@^5.7.3: + version "5.10.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177" + integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA== + dependencies: + clone-deep "^4.0.1" + flat "^5.0.2" + wildcard "^2.0.0" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@^5.0.0: + version "5.93.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.93.0.tgz#2e89ec7035579bdfba9760d26c63ac5c3462a5e5" + integrity sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^1.0.5" + "@webassemblyjs/ast" "^1.12.1" + "@webassemblyjs/wasm-edit" "^1.12.1" + "@webassemblyjs/wasm-parser" "^1.12.1" + acorn "^8.7.1" + acorn-import-attributes "^1.9.5" + browserslist "^4.21.10" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.17.0" + es-module-lexer "^1.2.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.11" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.2.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.3.10" + watchpack "^2.4.1" + webpack-sources "^3.2.3" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== From 5212a6ba5b2e0e11ee707af8eb378b1292749068 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Fri, 30 Aug 2024 22:26:51 +0800 Subject: [PATCH 2/4] Make sure the content script is only injected once --- pkg/extension-v3/src/background.ts | 4 +-- .../src/scripts/content/content.ts | 26 ++++++++++++++----- pkg/extension-v3/webpack.config.js | 1 - 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/pkg/extension-v3/src/background.ts b/pkg/extension-v3/src/background.ts index 52d7242e4..c92edf726 100644 --- a/pkg/extension-v3/src/background.ts +++ b/pkg/extension-v3/src/background.ts @@ -57,7 +57,7 @@ browserAPI.action.onClicked.addListener(async (tab) => { try { const scriptsLoaded = await scriptsAlreadyLoaded(tabId) if (!scriptsLoaded) { - await browserAPI.scripting.executeScript({ + await chrome.scripting.executeScript({ target: { tabId }, files: ['content.js'], }) @@ -65,6 +65,6 @@ browserAPI.action.onClicked.addListener(async (tab) => { } catch (err) { console.log('[omnivore] error injecting content script: ', err) } - chrome.tabs.sendMessage(tabId, { message: 'showToolbar' }) + chrome.tabs.sendMessage(tabId, { message: 'savePage' }) } }) diff --git a/pkg/extension-v3/src/scripts/content/content.ts b/pkg/extension-v3/src/scripts/content/content.ts index 6fefab6fb..324202bd5 100644 --- a/pkg/extension-v3/src/scripts/content/content.ts +++ b/pkg/extension-v3/src/scripts/content/content.ts @@ -20,11 +20,7 @@ const sendContentToServiceWorker = async (content: string) => { } } -// Capture content then send it to the background script -;(async () => { - const clientRequestId = uuidv4() - console.log('[omnivore] v3 extension triggered') - +const setupToolbar = async (clientRequestId: string) => { // toolbar message listener chrome.runtime.onMessage.addListener( async (request, sender, sendResponse) => { @@ -53,6 +49,14 @@ const sendContentToServiceWorker = async (content: string) => { } } ) + await showToolbar(clientRequestId) +} + +const savePage = async () => { + const clientRequestId = uuidv4() + console.log('[omnivore] v3 extension triggered') + + await setupToolbar(clientRequestId) const content = await collectPageContent() console.log('[omnivore] collected page content: ', content) @@ -71,4 +75,14 @@ const sendContentToServiceWorker = async (content: string) => { } catch (err) { console.log('error sending content: ', err) } -})() +} + +// toolbar message listener +chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => { + switch (request.message) { + case 'savePage': + await savePage() + sendResponse({ success: true }) + return + } +}) diff --git a/pkg/extension-v3/webpack.config.js b/pkg/extension-v3/webpack.config.js index 8e135d0e0..cfea0e2a7 100644 --- a/pkg/extension-v3/webpack.config.js +++ b/pkg/extension-v3/webpack.config.js @@ -39,7 +39,6 @@ module.exports = { new CopyWebpackPlugin({ patterns: [ { from: 'src/manifest.json', to: 'manifest.json' }, - { from: 'src/styles.css', to: 'styles.css' }, { from: 'src/icons', to: 'icons' }, { from: 'src/images', to: 'images' }, { from: 'src/views', to: 'views' }, From e8998581f040c68c73ed9e0ae5b4a0dc8033d0d1 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Fri, 30 Aug 2024 22:39:19 +0800 Subject: [PATCH 3/4] Implement addNote button --- .../src/scripts/content/toolbar.ts | 88 ++++++++++++++++++- pkg/extension-v3/src/scripts/utils.ts | 8 +- 2 files changed, 89 insertions(+), 7 deletions(-) diff --git a/pkg/extension-v3/src/scripts/content/toolbar.ts b/pkg/extension-v3/src/scripts/content/toolbar.ts index aa93a48a7..db2908039 100644 --- a/pkg/extension-v3/src/scripts/content/toolbar.ts +++ b/pkg/extension-v3/src/scripts/content/toolbar.ts @@ -1,5 +1,5 @@ import { ToolbarMessage, ToolbarStatus } from '../types' -import { getStorageItem } from '../utils' +import { getStorageItem, setStorage } from '../utils' const systemIcons: { [key: string]: string } = { waiting: '
', @@ -269,6 +269,10 @@ const toggleRow = (rowId: string) => { } } +const noteCacheKey = () => { + return `cached-note-${document.location.href}` +} + // // Button functions // @@ -278,7 +282,7 @@ function login() { closeToolbarLater() } -const addNote = () => { +const addNote = async () => { console.log('[omnivore] adding note') cancelAutoDismiss() @@ -287,6 +291,86 @@ const addNote = () => { 'data-omnivore-client-request-id' ) console.log('client request id: ', clientRequestId) + + const cachedNoteKey = noteCacheKey() + + cancelAutoDismiss() + toggleRow('#omnivore-add-note-row') + + const noteArea = + currentToastEl?.shadowRoot?.querySelector( + '#omnivore-add-note-textarea' + ) + + if (noteArea) { + if (cachedNoteKey) { + const existingNote = + ((await getStorageItem(cachedNoteKey)) as string) ?? '' + noteArea.value = existingNote + } + + if (noteArea.value) { + noteArea.select() + } else { + noteArea.focus() + } + + noteArea.addEventListener('input', (event) => { + ;(async () => { + const note: Record = {} + note[cachedNoteKey] = (event.target as HTMLTextAreaElement).value + await setStorage(note) + })() + }) + + noteArea.onkeydown = (e: KeyboardEvent) => { + e.cancelBubble = true + e.stopPropagation() + // Handle the enter key + if (e.keyCode == 13 && (e.metaKey || e.ctrlKey)) { + updateStatusBox( + '#omnivore-add-note-status', + 'waiting', + 'Adding note...', + undefined + ) + + // browserApi.runtime.sendMessage({ + // action: ACTIONS.AddNote, + // payload: { + // ctx: ctx, + // note: noteArea.value, + // }, + // }) + } + } + } + + const form = currentToastEl?.shadowRoot?.querySelector( + '#omnivore-add-note-form' + ) + + if (form) { + form.onsubmit = (event) => { + updateStatusBox( + '#omnivore-add-note-status', + 'waiting', + 'Adding note...', + undefined + ) + + // browserApi.runtime.sendMessage({ + // action: ACTIONS.AddNote, + // payload: { + // ctx: ctx, + // note: event.target.elements.title.value, + // }, + // }) + + event.preventDefault() + event.stopPropagation() + } + } } const readNow = () => { diff --git a/pkg/extension-v3/src/scripts/utils.ts b/pkg/extension-v3/src/scripts/utils.ts index cbb373c2e..08b0e3f59 100644 --- a/pkg/extension-v3/src/scripts/utils.ts +++ b/pkg/extension-v3/src/scripts/utils.ts @@ -7,11 +7,9 @@ export const getStorageItem = async (singleKey: string) => { }) } -// const setStorage(itemsToSet) { -// return new Promise((resolve) => { -// browserApi.storage.local.set(itemsToSet, resolve) -// }) -// } +export const setStorage = (itemsToSet: Record) => { + return chrome.storage.local.set(itemsToSet) +} // function removeStorage(itemsToRemove) { // return new Promise((resolve) => { From aae04b6cba1033a721e81d46b46318c48623498c Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Sat, 31 Aug 2024 16:07:13 +0800 Subject: [PATCH 4/4] More separation work for tasks, implement archive and update note --- pkg/extension-v3/src/background.ts | 87 +++++--- .../src/scripts/content/content.ts | 66 +++--- .../src/scripts/content/toolbar.ts | 170 +++++++++++---- pkg/extension-v3/src/scripts/omnivore-api.ts | 199 ++++++++++++++---- pkg/extension-v3/src/scripts/types.ts | 51 +++++ pkg/extension-v3/src/task-queue.ts | 96 +++++++++ 6 files changed, 530 insertions(+), 139 deletions(-) create mode 100644 pkg/extension-v3/src/task-queue.ts diff --git a/pkg/extension-v3/src/background.ts b/pkg/extension-v3/src/background.ts index c92edf726..4a4651268 100644 --- a/pkg/extension-v3/src/background.ts +++ b/pkg/extension-v3/src/background.ts @@ -1,40 +1,62 @@ -import { savePageRequest } from './scripts/omnivore-api' -import { isSavePageInput } from './scripts/types' +import { v4 as uuidv4 } from 'uuid' +import { addNoteToLibraryItem, savePageRequest } from './scripts/omnivore-api' +import { + isAddNoteInput, + isEnqueueTaskMessage, + isSavePageInput, +} from './scripts/types' +import { TaskQueue } from './task-queue' const browserAPI = typeof browser !== 'undefined' ? browser : chrome +const taskQueues: Record = {} + chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => { console.log('message: ', message, 'sender', sender.tab?.id) + + const tabId = sender.tab?.id if (message.action === 'savePage' && isSavePageInput(message)) { - try { - const result = await savePageRequest({ - url: message.url, - title: message.title, - clientRequestId: message.clientRequestId, - originalContent: message.originalContent, - }) - if (sender.tab?.id) { - switch (result) { - case 'success': - chrome.tabs.sendMessage(sender.tab?.id, { - message: 'startToolbarDismiss', - status: 'success', - }) - break - case 'failure': - chrome.tabs.sendMessage(sender.tab?.id, { - message: 'startToolbarDismiss', - status: 'failure', - }) - break - case 'unauthorized': - chrome.tabs.sendMessage(sender.tab?.id, { - message: 'showLoggedOutToolbar', - }) - break - } + const { result, libraryItemId } = await savePageRequest({ + url: message.url, + title: message.title, + clientRequestId: message.clientRequestId, + originalContent: message.originalContent, + }) + console.log('result: ', result, 'libraryItemId', libraryItemId) + if (tabId) { + switch (result) { + case 'success': + chrome.tabs.sendMessage(tabId, { + message: 'startToolbarDismiss', + status: 'success', + }) + if (libraryItemId) { + const taskQueue = taskQueues[message.clientRequestId] + taskQueue.setReady(tabId, libraryItemId) + } + break + case 'failure': + chrome.tabs.sendMessage(tabId, { + message: 'startToolbarDismiss', + status: 'failure', + }) + break + case 'unauthorized': + chrome.tabs.sendMessage(tabId, { + message: 'showLoggedOutToolbar', + }) + break } - } catch (err) {} + } + } else if (message.action == 'enqueueTask' && isEnqueueTaskMessage(message)) { + const taskQueue = taskQueues[message.clientRequestId] + console.log('appending to task queue: ', taskQueue) + // const result = await addNoteToLibraryItem({ + // clientRequestId: message.clientRequestId, + // note: message.note, + // }) + console.log('enqueing task message: ', message) + taskQueue.enqueue(message) } return true }) @@ -65,6 +87,9 @@ browserAPI.action.onClicked.addListener(async (tab) => { } catch (err) { console.log('[omnivore] error injecting content script: ', err) } - chrome.tabs.sendMessage(tabId, { message: 'savePage' }) + + const clientRequestId = uuidv4() + taskQueues[clientRequestId] = new TaskQueue() + chrome.tabs.sendMessage(tabId, { message: 'savePage', clientRequestId }) } }) diff --git a/pkg/extension-v3/src/scripts/content/content.ts b/pkg/extension-v3/src/scripts/content/content.ts index 324202bd5..27cf862d7 100644 --- a/pkg/extension-v3/src/scripts/content/content.ts +++ b/pkg/extension-v3/src/scripts/content/content.ts @@ -1,9 +1,9 @@ -import { v4 as uuidv4 } from 'uuid' import { SavePageInput, ToolbarMessage } from '../types' import { showLoggedOutToolbar, showToolbar, startToolbarDismiss, + updateToolbarStatus, } from './toolbar' const collectPageContent = async (): Promise => { @@ -12,49 +12,43 @@ const collectPageContent = async (): Promise => { return mainContent } -const sendContentToServiceWorker = async (content: string) => { - try { - await chrome.runtime.sendMessage({ action: 'savePage', data: content }) - } catch (err) { - console.log('error sending content: ', err) +const handleToolbarMessage = async ( + request: any, + sender: chrome.runtime.MessageSender, + sendResponse: (response?: any) => void +) => { + console.log('[omnivore] content script message:', request) + + switch (request.message) { + case 'showLoggedOutToolbar': + showLoggedOutToolbar() + sendResponse({ success: true }) + break + case 'updateToolbar': + updateToolbarStatus(request.status, request.task) + sendResponse({ success: true }) + break + case 'startToolbarDismiss': + startToolbarDismiss(request as ToolbarMessage) + sendResponse({ success: true }) + return + default: + sendResponse({ success: false }) + return } } const setupToolbar = async (clientRequestId: string) => { // toolbar message listener - chrome.runtime.onMessage.addListener( - async (request, sender, sendResponse) => { - console.log( - '[omnivore] content script message:', - clientRequestId, - request - ) + if (!chrome.runtime.onMessage.hasListener(handleToolbarMessage)) { + chrome.runtime.onMessage.addListener(handleToolbarMessage) + } - switch (request.message) { - case 'showToolbar': - await showToolbar(clientRequestId) - sendResponse({ success: true }) - return - case 'showLoggedOutToolbar': - showLoggedOutToolbar() - sendResponse({ success: true }) - break - case 'startToolbarDismiss': - startToolbarDismiss(request as ToolbarMessage) - sendResponse({ success: true }) - return - default: - sendResponse({ success: false }) - return - } - } - ) await showToolbar(clientRequestId) } -const savePage = async () => { - const clientRequestId = uuidv4() - console.log('[omnivore] v3 extension triggered') +const savePage = async (clientRequestId: string) => { + console.log('[omnivore] v3 extension triggered: ', clientRequestId) await setupToolbar(clientRequestId) @@ -81,7 +75,7 @@ const savePage = async () => { chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => { switch (request.message) { case 'savePage': - await savePage() + await savePage(request.clientRequestId) sendResponse({ success: true }) return } diff --git a/pkg/extension-v3/src/scripts/content/toolbar.ts b/pkg/extension-v3/src/scripts/content/toolbar.ts index db2908039..a64d4edc9 100644 --- a/pkg/extension-v3/src/scripts/content/toolbar.ts +++ b/pkg/extension-v3/src/scripts/content/toolbar.ts @@ -1,4 +1,4 @@ -import { ToolbarMessage, ToolbarStatus } from '../types' +import { AddNoteInput, ToolbarMessage, ToolbarStatus } from '../types' import { getStorageItem, setStorage } from '../utils' const systemIcons: { [key: string]: string } = { @@ -20,16 +20,10 @@ const createToastContainer = async (clientRequestId: string) => { console.log('===== CREATING TOAST CONTAINER ===== ') const file = await fetch(chrome.runtime.getURL('views/toast.html')) const html = await file.text() - const disableAutoDismiss = await getStorageItem('disableAutoDismiss') const root = document.createElement('div') root.tabIndex = 0 root.id = 'omnivore-extension-root' - if (disableAutoDismiss) { - root.setAttribute('data-disable-auto-dismiss', 'true') - } - root.setAttribute('data-omnivore-client-request-id', clientRequestId) - root.setAttribute('data-omnivore-client-request-id', clientRequestId) root.attachShadow({ mode: 'open' }) root.style.opacity = '1.0' @@ -67,6 +61,14 @@ export const showToolbar = async (clientRequestId: string) => { currentToastEl = await createToastContainer(clientRequestId) } + const disableAutoDismiss = await getStorageItem('disableAutoDismiss') + if (disableAutoDismiss) { + currentToastEl?.setAttribute('data-disable-auto-dismiss', 'true') + } + currentToastEl?.setAttribute( + 'data-omnivore-client-request-id', + clientRequestId + ) ;(currentToastEl as HTMLDivElement)?.focus({ preventScroll: true, }) @@ -79,7 +81,10 @@ const autoDismissTime = async () => { return !Number.isNaN(Number(strVal)) ? Number(strVal) : 2500 } -const updateToolbarStatus = async (status: ToolbarStatus) => { +export const updateToolbarStatus = async ( + status: ToolbarStatus, + task: string | undefined = undefined +) => { const currentToastEl = document.querySelector('#omnivore-extension-root') const statusBox = currentToastEl?.shadowRoot?.querySelector( '.omnivore-toast-statusBox' @@ -99,6 +104,40 @@ const updateToolbarStatus = async (status: ToolbarStatus) => { break } } + + // Set a task specific message + if (task) { + if (task == 'addNote' && status == 'failure') { + updateStatusBox( + '#omnivore-add-note-status', + 'failure', + 'Error adding note...', + undefined + ) + } + if (task == 'addNote' && status == 'success') { + updateStatusBox( + '#omnivore-add-note-status', + 'success', + 'Note updated.', + 2500 + ) + setTimeout(() => { + toggleRow('#omnivore-add-note-status') + }, 3000) + } + if (task == 'archive') { + updateStatusBox( + '#omnivore-extra-status', + status, + status == 'success' ? 'Success' : 'Error', + status == 'success' ? 2500 : undefined + ) + if (status == 'success') { + closeToolbarLater() + } + } + } } const cancelAutoDismiss = () => { @@ -147,11 +186,11 @@ const connectButtons = (root: HTMLElement) => { // { id: '#omnivore-toast-edit-title-btn', func: editTitle }, // { id: '#omnivore-toast-edit-labels-btn', func: editLabels }, { id: '#omnivore-toast-read-now-btn', func: readNow }, - // { id: '#omnivore-open-menu-btn', func: openMenu }, + { id: '#omnivore-open-menu-btn', func: openMenu }, { id: '#omnivore-toast-close-btn', func: closeToolbar }, { id: '#omnivore-toast-login-btn', func: login }, - // { id: '#omnivore-toast-archive-btn', func: archive }, - // { id: '#omnivore-toast-delete-btn', func: deleteItem }, + { id: '#omnivore-toast-archive-btn', func: archive }, + { id: '#omnivore-toast-delete-btn', func: deleteItem }, ] for (const btnInfo of btns) { @@ -214,7 +253,8 @@ const updateStatusBox = ( } })() if (image && statusBox) { - statusBox.innerHTML = `${image}${message}` + const color = state == 'failure' ? 'red' : 'unset' + statusBox.innerHTML = `${image}${message}` } else if (statusBox) { statusBox.innerHTML = message } @@ -273,15 +313,28 @@ const noteCacheKey = () => { return `cached-note-${document.location.href}` } +const getClientRequestId = () => { + const currentToastEl = document.querySelector('#omnivore-extension-root') + const clientRequestId = currentToastEl?.getAttribute( + 'data-omnivore-client-request-id' + ) + return clientRequestId +} + // // Button functions // -function login() { +const login = () => { window.open(new URL(`/login`, process.env.OMNIVORE_URL), '_blank') closeToolbarLater() } +const openMenu = () => { + cancelAutoDismiss() + toggleRow('#omnivore-extra-buttons-row') +} + const addNote = async () => { console.log('[omnivore] adding note') cancelAutoDismiss() @@ -291,6 +344,16 @@ const addNote = async () => { 'data-omnivore-client-request-id' ) console.log('client request id: ', clientRequestId) + if (!clientRequestId) { + // TODO: move into an error state + updateStatusBox( + '#omnivore-add-note-status', + 'failure', + 'Error adding note...', + undefined + ) + return + } const cachedNoteKey = noteCacheKey() @@ -315,18 +378,17 @@ const addNote = async () => { noteArea.focus() } - noteArea.addEventListener('input', (event) => { - ;(async () => { - const note: Record = {} - note[cachedNoteKey] = (event.target as HTMLTextAreaElement).value - await setStorage(note) - })() + noteArea.addEventListener('input', async (event) => { + const note: Record = {} + note[cachedNoteKey] = (event.target as HTMLTextAreaElement).value + await setStorage(note) }) - noteArea.onkeydown = (e: KeyboardEvent) => { - e.cancelBubble = true + noteArea.onkeydown = async (e: KeyboardEvent) => { + // e.preventDefault() e.stopPropagation() // Handle the enter key + console.log('handling the enter key: ', e.keyCode) if (e.keyCode == 13 && (e.metaKey || e.ctrlKey)) { updateStatusBox( '#omnivore-add-note-status', @@ -335,13 +397,7 @@ const addNote = async () => { undefined ) - // browserApi.runtime.sendMessage({ - // action: ACTIONS.AddNote, - // payload: { - // ctx: ctx, - // note: noteArea.value, - // }, - // }) + await saveNote(clientRequestId, noteArea.value) } } } @@ -351,7 +407,8 @@ const addNote = async () => { ) if (form) { - form.onsubmit = (event) => { + form.onsubmit = async (event) => { + console.log('handling form submit') updateStatusBox( '#omnivore-add-note-status', 'waiting', @@ -359,13 +416,9 @@ const addNote = async () => { undefined ) - // browserApi.runtime.sendMessage({ - // action: ACTIONS.AddNote, - // payload: { - // ctx: ctx, - // note: event.target.elements.title.value, - // }, - // }) + if (noteArea) { + await saveNote(clientRequestId, noteArea.value) + } event.preventDefault() event.stopPropagation() @@ -373,6 +426,34 @@ const addNote = async () => { } } +const archive = async (event: Event) => { + const clientRequestId = getClientRequestId() + try { + await chrome.runtime.sendMessage({ + action: 'enqueueTask', + task: 'archive', + clientRequestId, + }) + } catch (err) { + console.log('error archiving item') + } + event.preventDefault() +} + +const deleteItem = async (event: Event) => { + const clientRequestId = getClientRequestId() + try { + await chrome.runtime.sendMessage({ + action: 'enqueueTask', + task: 'delete', + clientRequestId, + }) + } catch (err) { + console.log('error archiving item') + } + event.preventDefault() +} + const readNow = () => { cancelAutoDismiss() @@ -404,3 +485,20 @@ const closeToolbar = () => { currentToastEl.remove() } } + +// +// API interactions +// + +const saveNote = async (clientRequestId: string, note: string) => { + try { + await chrome.runtime.sendMessage({ + action: 'enqueueTask', + task: 'addNote', + note, + clientRequestId, + }) + } catch (err) { + console.log('error adding note: ', err) + } +} diff --git a/pkg/extension-v3/src/scripts/omnivore-api.ts b/pkg/extension-v3/src/scripts/omnivore-api.ts index 2605d3100..8e0d4fa3b 100644 --- a/pkg/extension-v3/src/scripts/omnivore-api.ts +++ b/pkg/extension-v3/src/scripts/omnivore-api.ts @@ -1,8 +1,10 @@ -import { SavePageData } from './types' +import { ArticleData, SavePageData, SetLinkArchivedData } from './types' import { getStorageItem } from './utils' const apiUrl = process.env.OMNIVORE_GRAPHQL_URL ?? '' +export type ApiResult = 'success' | 'failure' | 'unauthorized' + const gqlRequest = async (query: string) => { const apiKey = (await getStorageItem('apiKey')) as string | undefined let headers = { @@ -32,8 +34,6 @@ const gqlRequest = async (query: string) => { } } -export type SavePageRequestResult = 'success' | 'failure' | 'unauthorized' - export async function savePageRequest(input: { url: string title: string @@ -64,11 +64,135 @@ export async function savePageRequest(input: { if (data.savePage?.errorCodes?.length) { console.log('[omnivore] api: error saving page:', data) if (data.savePage.errorCodes.indexOf('UNAUTHORIZED') > -1) { + console.log('[omnivore] api is not authorized') + return { result: 'unauthorized' } + } + return { result: 'failure' } + } + return { result: 'success', libraryItemId: data.savePage?.clientRequestId } +} + +export async function addNoteToLibraryItem(input: { + libraryItemId: string + note: string +}) { + const query = JSON.stringify({ + query: `query GetArticle( + $username: String! + $slug: String! + $includeFriendsHighlights: Boolean + ) { + article(username: $username, slug: $slug) { + ... on ArticleSuccess { + article { + highlights(input: { includeFriends: $includeFriendsHighlights }) { + ...HighlightFields + } + } + } + ... on ArticleError { + errorCodes + } + } + } + fragment HighlightFields on Highlight { + id + type + annotation + } + `, + variables: { + username: 'me', + slug: input.libraryItemId, + includeFriendsHighlights: false, + }, + }) + + const data = (await gqlRequest(query)) as ArticleData + if (data.article?.errorCodes?.length) { + console.log('[omnivore] api: error getting article:', data) + if (data.article.errorCodes.indexOf('UNAUTHORIZED') > -1) { console.log('[omnivore] api is not authorized') return 'unauthorized' } return 'failure' } + + console.log('DATA.ARTICLE: ', data.article) + const existingNote = data.article?.highlights?.find((h) => h.type == 'NOTE') + + // if (existingNote) { + // const mutation = JSON.stringify({ + // query: ` + // mutation UpdateHighlight($input: UpdateHighlightInput!) { + // updateHighlight(input: $input) { + // ... on UpdateHighlightSuccess { + // highlight { + // id + // } + // } + // ... on UpdateHighlightError { + // errorCodes + // } + // } + // } + // `, + // variables: { + // input: { + // highlightId: existingNote.id, + // annotation: existingNote.annotation + // ? existingNote.annotation + '\n\n' + note + // : note, + // }, + // }, + // }) + // const result = await gqlRequest(apiUrl, mutation) + // if ( + // !result.updateHighlight || + // result.updateHighlight['errorCodes'] || + // !result.updateHighlight.highlight + // ) { + // console.log('GQL Error updating note:', result) + // return + // } + // return result.updateHighlight.highlight.id + // } else { + // const mutation = JSON.stringify({ + // query: ` + // mutation CreateHighlight($input: CreateHighlightInput!) { + // createHighlight(input: $input) { + // ... on CreateHighlightSuccess { + // highlight { + // id + // } + // } + // ... on CreateHighlightError { + // errorCodes + // } + // } + // } + // `, + // variables: { + // input: { + // id: noteId, + // shortId: shortId, + // type: 'NOTE', + // articleId: pageId, + // annotation: note, + // }, + // }, + // }) + // const result = await gqlRequest(apiUrl, mutation) + // if ( + // !result.createHighlight || + // result.createHighlight['errorCodes'] || + // !result.createHighlight.highlight + // ) { + // console.log('GQL Error setting note:', result) + // return + // } + // return result.createHighlight.highlight.id + // } return 'success' } @@ -325,40 +449,43 @@ export async function savePageRequest(input: { // } // } -// async function archive(apiUrl, pageId) { -// const mutation = JSON.stringify({ -// query: `mutation SetLinkArchived($input: ArchiveLinkInput!) { -// setLinkArchived(input: $input) { -// ... on ArchiveLinkSuccess { -// linkId -// message -// } -// ... on ArchiveLinkError { -// message -// errorCodes -// } -// } -// } -// `, -// variables: { -// input: { -// linkId: pageId, -// archived: true, -// }, -// }, -// }) +export const archiveLibraryItem = async ( + libraryItemId: string +): Promise => { + const mutation = JSON.stringify({ + query: `mutation SetLinkArchived($input: ArchiveLinkInput!) { + setLinkArchived(input: $input) { + ... on ArchiveLinkSuccess { + linkId + message + } + ... on ArchiveLinkError { + message + errorCodes + } + } + } + `, + variables: { + input: { + linkId: libraryItemId, + archived: true, + }, + }, + }) -// const data = await gqlRequest(apiUrl, mutation) -// if ( -// !data.setLinkArchived || -// data.setLinkArchived['errorCodes'] || -// !data.setLinkArchived.linkId -// ) { -// console.log('GQL Error archiving:', data) -// throw new Error('Error archiving.') -// } -// return data.setLinkArchived.linkId -// } + const data = (await gqlRequest(mutation)) as SetLinkArchivedData + if (data.setLinkArchived?.errorCodes?.length) { + console.log('[omnivore] api: error getting article:', data) + if (data.setLinkArchived.errorCodes.indexOf('UNAUTHORIZED') > -1) { + console.log('[omnivore] api is not authorized') + return 'unauthorized' + } + return 'failure' + } + + return 'success' +} // async function deleteItem(apiUrl, pageId) { // const mutation = JSON.stringify({ diff --git a/pkg/extension-v3/src/scripts/types.ts b/pkg/extension-v3/src/scripts/types.ts index 0ddee0571..5caf47104 100644 --- a/pkg/extension-v3/src/scripts/types.ts +++ b/pkg/extension-v3/src/scripts/types.ts @@ -14,6 +14,30 @@ export interface SavePageResult { errorCodes?: string[] } +export interface Highlight { + id: string + type: string + annotation: string +} + +export interface ArticleResult { + highlights?: Highlight[] + errorCodes?: string[] +} +export interface ArticleData { + article?: ArticleResult +} + +export interface SetLinkArchivedResult { + linkId?: string + message?: string + errorCodes?: string[] +} + +export interface SetLinkArchivedData { + setLinkArchived?: SetLinkArchivedResult +} + export interface SavePageInput { url: string title: string @@ -21,6 +45,17 @@ export interface SavePageInput { originalContent: string } +export interface AddNoteInput { + clientRequestId: string + note: string +} + +export interface TaskInput { + clientRequestId: string + task: 'addNote' | 'archive' + note?: string +} + export function isSavePageResult(obj: any): obj is SavePageResult { return ( typeof obj === 'object' && @@ -49,3 +84,19 @@ export function isSavePageInput(obj: any): obj is SavePageInput { typeof obj.originalContent === 'string' ) } + +export function isAddNoteInput(obj: any): obj is AddNoteInput { + return ( + typeof obj === 'object' && + typeof obj.note === 'string' && + typeof obj.clientRequestId === 'string' + ) +} + +export function isEnqueueTaskMessage(obj: any): obj is TaskInput { + return ( + typeof obj === 'object' && + typeof obj.task === 'string' && + typeof obj.clientRequestId === 'string' + ) +} diff --git a/pkg/extension-v3/src/task-queue.ts b/pkg/extension-v3/src/task-queue.ts new file mode 100644 index 000000000..59114b5fd --- /dev/null +++ b/pkg/extension-v3/src/task-queue.ts @@ -0,0 +1,96 @@ +import { + addNoteToLibraryItem, + archiveLibraryItem, +} from './scripts/omnivore-api' +import { TaskInput } from './scripts/types' + +export class TaskQueue { + private queue: Array = [] + private isRunning: boolean = false + private isReady: boolean = false + + private tabId: number | undefined + private libraryItemId: string | undefined + + constructor() {} + + enqueue(task: TaskInput): void { + this.queue.push(task) + + // Only run the next task if the queue is ready + if (this.isReady) { + this.runNext() + } + } + + private async runNext(): Promise { + if (this.isRunning || this.queue.length === 0 || !this.isReady) return + + this.isRunning = true + const task = this.queue.shift() + + if (task) { + try { + await this.executeTask(task) + } catch (err) { + console.error('Task failed:', err) + } finally { + this.isRunning = false + if (this.isReady) { + this.runNext() + } + } + } + } + + private executeTask = async (task: TaskInput) => { + console.log('executing task: ', task) + if (!this.libraryItemId) { + throw Error('Attempting to execute queue that is not ready.') + } + + try { + let success = false + switch (task.task) { + case 'archive': { + await archiveLibraryItem(this.libraryItemId) + success = true + break + } + case 'addNote': { + await addNoteToLibraryItem({ + note: task.note || '', + libraryItemId: this.libraryItemId, + }) + success = true + break + } + } + if (success && this.tabId) { + chrome.tabs.sendMessage(this.tabId, { + message: 'updateToolbar', + status: 'success', + task: task.task, + }) + } + } catch (err) { + console.log('[omnivore] task queue error: ', err) + if (this.tabId) { + console.log('sending error message') + chrome.tabs.sendMessage(this.tabId, { + message: 'updateToolbar', + status: 'failure', + task: task.task, + }) + } + } + } + + setReady(tabId: number, libraryItemId: string): void { + console.log('setting ready') + this.tabId = tabId + this.libraryItemId = libraryItemId + this.isReady = true + this.runNext() + } +}