From e829f38935a3d355ba6acb24cbae09419deebf39 Mon Sep 17 00:00:00 2001 From: cyhhao Date: Wed, 7 Dec 2022 17:04:39 +0800 Subject: [PATCH] add storage framework --- .gitignore | 2 +- package.json | 6 +- src/git/git-remote-helper.ts | 339 +++++++++++++++++++++++++++++++++++ src/git/git.ts | 102 +++++++++++ src/git/log.ts | 6 + src/index.ts | 30 ++-- src/storage/ETHStorage.ts | 37 ++++ src/storage/storage.ts | 24 +++ yarn.lock | 176 ++++++++++++++---- 9 files changed, 666 insertions(+), 56 deletions(-) create mode 100644 src/git/git-remote-helper.ts create mode 100644 src/git/git.ts create mode 100644 src/git/log.ts create mode 100644 src/storage/ETHStorage.ts create mode 100644 src/storage/storage.ts diff --git a/.gitignore b/.gitignore index dbd1f42..7f5603c 100644 --- a/.gitignore +++ b/.gitignore @@ -128,6 +128,6 @@ dist .yarn/build-state.yml .yarn/install-state.gz .pnp.* - +.DS_Store bin/ dist/ \ No newline at end of file diff --git a/package.json b/package.json index fbf6fa0..48619c0 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,11 @@ "license": "MIT", "dependencies": { "debug": "^4.3.4", - "git-remote-helper": "^0.4.0" + "level": "^8.0.0", + "rxjs": "^6.6.3", + "rxjs-async-map": "^0.2.0", + "rxjs-stream": "^3.2.1", + "superpathjoin": "^2.0.1" }, "scripts": { "build": "yarn run clean && tsc", diff --git a/src/git/git-remote-helper.ts b/src/git/git-remote-helper.ts new file mode 100644 index 0000000..5250528 --- /dev/null +++ b/src/git/git-remote-helper.ts @@ -0,0 +1,339 @@ +import debug from 'debug'; +import { asyncMap } from 'rxjs-async-map'; +import { rxToStream, streamToStringRx } from 'rxjs-stream'; +import { filter, map, mergeMap, scan, tap } from 'rxjs/operators'; +import { superpathjoin as join } from 'superpathjoin'; + +// TODO Add tests + +enum GitCommands { + capabilities = 'capabilities', + option = 'option', + list = 'list', + push = 'push', + fetch = 'fetch', +} +const ONE_LINE_COMMANDS = [ + GitCommands.capabilities, + GitCommands.option, + GitCommands.list, +]; + +const logError = (...args: any) => { + console.error(...args); +}; +const log = debug('git-remote-helper'); +const logIo = log.extend('io'); +const logInput = logIo.extend('input'); +const logOutput = logIo.extend('output'); + +export type PushRef = { src: string; dst: string; force: boolean }; +export type FetchRef = { ref: string; oid: string }; + +type CommandCapabilities = { + command: GitCommands.capabilities; +}; +type CommandOption = { + command: GitCommands.option; + key: string; + value: string; +}; +type CommandList = { + command: GitCommands.list; + forPush: boolean; +}; +type CommandPush = { + command: GitCommands.push; + refs: PushRef[]; +}; +type CommandFetch = { + command: GitCommands.fetch; + refs: FetchRef[]; +}; +export type Command = + | CommandCapabilities + | CommandOption + | CommandList + | CommandPush + | CommandFetch; + +/** + * These are parameters which are passed to every api callback + */ +export type ApiBaseParams = { + gitdir: string; + /** + * The remote name, or the remote URL if a name is not provided. Supplied by + * the native git client. + */ + remoteName: string; + /** + * The remote URL passed by the native git client. + * + * NOTE: It will not contain the leading `HELPER::`, only the part after that. + */ + remoteUrl: string; +}; + + +type HandlePush = ( + params: ApiBaseParams & { refs: PushRef[] } +) => Promise; +type HandleFetch = ( + params: ApiBaseParams & { + refs: FetchRef[]; + } +) => Promise; + +type ApiBase = { + /** + * Optional init() hook which will be called each time that the + * git-remote-helper is invoked before any other APIs are called. It will be + * awaited, so you can safely do setup steps here and trust they will be + * finished before any of the other API methods are invoked. + */ + init?: (params: ApiBaseParams) => Promise; + list: ( + params: ApiBaseParams & { + forPush: boolean; + } + ) => Promise; + handlePush?: HandlePush; + handleFetch?: HandleFetch; +}; +type ApiPush = ApiBase & { + handlePush: HandlePush; + handleFetch?: undefined; +}; +type ApiFetch = ApiBase & { + handlePush?: undefined; + handleFetch: HandleFetch; +}; +type ApiBoth = ApiBase & { + handlePush: HandlePush; + handleFetch: HandleFetch; +}; +type Api = ApiPush | ApiFetch | ApiBoth; + +const GitRemoteHelper = async ({ + env, + api, + stdin, + stdout, +}: { + env: typeof process.env; + stdin: typeof process.stdin; + stdout: typeof process.stdout; + api: Api; +}) => { + const inputStream = streamToStringRx(stdin); + + const getDir = () => { + if (typeof env['GIT_DIR'] !== 'string') { + throw new Error('Missing GIT_DIR env #tVJpoU'); + } + return env['GIT_DIR']; + }; + const gitdir = join(process.cwd(), getDir()); + + const [, , remoteName, remoteUrl] = process.argv; + + const capabilitiesResponse = + [GitCommands.option, GitCommands.push, GitCommands.fetch] + .filter(option => { + if (option === GitCommands.option) { + return true; + } else if (option === GitCommands.push) { + return typeof api.handlePush === 'function'; + } else if (option === GitCommands.fetch) { + return typeof api.handleFetch === 'function'; + } else { + throw new Error('Unknown option #GDhBnb'); + } + }) + .join('\n') + '\n\n'; + + log('Startup #p6i3kB', { + gitdir, + remoteName, + remoteUrl, + capabilitiesResponse, + }); + + if (typeof api.init === 'function') { + await api.init({ gitdir, remoteName, remoteUrl }); + } + + const commands = inputStream.pipe( + tap(line => { + logInput('Got raw input line #gARMUQ', JSON.stringify(line)); + }), + // The `line` can actually contain multiple lines, so we split them out into + // multiple pieces and recombine them again + map(line => line.split('\n')), + mergeMap(lineGroup => lineGroup), + // Commands include a trailing newline which we don't need + map(line => line.trimEnd()), + scan( + (acc, line) => { + log('Scanning #NH7FyX', JSON.stringify({ acc, line })); + // If we emitted the last value, then we ignore all of the current lines + // and start fresh on the next "batch" + const linesWaitingToBeEmitted = acc.emit ? [] : acc.lines; + + // When we hit an empty line, it's always the completion of a command + // block, so we always want to emit the lines we've been collecting. + // NOTE: We do not add the blank line onto the existing array of lines + // here, it gets dropped here. + if (line === '') { + if (linesWaitingToBeEmitted.length === 0) { + return { emit: false, lines: [] }; + } + + return { emit: true, lines: linesWaitingToBeEmitted }; + } + + // Some commands emit one line at a time and so do not get buffered + if (ONE_LINE_COMMANDS.find(command => line.startsWith(command))) { + // If we have other lines waiting for emission, something went wrong + if (linesWaitingToBeEmitted.length > 0) { + logError( + 'Got one line command with lines waiting #ompfQK', + JSON.stringify({ linesWaitingToBeEmitted }) + ); + throw new Error('Got one line command with lines waiting #evVyYv'); + } + + return { emit: true, lines: [line] }; + } + + // Otherwise, this line is part of a multi line command, so stick it + // into the "buffer" and do not emit + return { emit: false, lines: linesWaitingToBeEmitted.concat(line) }; + }, + { emit: false, lines: [] as string[] } + ), + tap(acc => { + log('Scan output #SAAmZ4', acc); + }), + filter(acc => acc.emit), + map(emitted => emitted.lines), + tap(lines => { + log('Buffer emptied #TRqQFc', JSON.stringify(lines)); + }) + ); + + // NOTE: Splitting this into 2 pipelines so typescript is happy that it + // produces a string + const output = commands.pipe( + // filter(lines => lines.length > 0), + // Build objects from the sequential lines + map( + (lines): Command => { + log('Mapping buffered line #pDqtRP', lines); + + const command = lines[0]; + + if (command.startsWith('capabilities')) { + return { command: GitCommands.capabilities }; + } else if (command.startsWith(GitCommands.list)) { + return { + command: GitCommands.list, + forPush: command.startsWith('list for-push'), + }; + } else if (command.startsWith(GitCommands.option)) { + const [, key, value] = command.split(' '); + return { command: GitCommands.option, key, value }; + } else if (command.startsWith(GitCommands.fetch)) { + // Lines for fetch commands look like: + // fetch sha1 branchName + const refs = lines.map(line => { + const [, oid, ref] = line.split(' '); + return { oid, ref }; + }); + + return { command: GitCommands.fetch, refs }; + } else if (command.startsWith(GitCommands.push)) { + // Lines for push commands look like this (the + means force push): + // push refs/heads/master:refs/heads/master + // push +refs/heads/master:refs/heads/master + const refs = lines.map(line => { + // Strip the leading `push ` from the line + const refsAndForce = line.slice(5); + const force = refsAndForce[0] === '+'; + const refs = force ? refsAndForce.slice(1) : refsAndForce; + const [src, dst] = refs.split(':'); + return { src, dst, force }; + }); + + return { command: GitCommands.push, refs }; + } + + throw new Error('Unknown command #Py9QTP'); + } + ), + asyncMap(async command => { + if (command.command === GitCommands.capabilities) { + log( + 'Returning capabilities #MJMFfj', + JSON.stringify({ command, capabilitiesResponse }) + ); + return capabilitiesResponse; + } else if (command.command === GitCommands.option) { + // TODO Figure out how to handle options properly + log( + 'Reporting option unsupported #WdUrzx', + JSON.stringify({ command }) + ); + return 'unsupported\n'; + } else if (command.command === GitCommands.list) { + const { forPush } = command; + try { + return api.list({ gitdir, remoteName, remoteUrl, forPush }); + } catch (error) { + console.error('api.list threw #93ROre'); + // console.error(error); + throw error; + } + } else if (command.command === GitCommands.push) { + log('Calling api.handlePush() #qpi4Ah'); + const { refs } = command; + if (typeof api.handlePush === 'undefined') { + throw new Error('api.handlePush undefined #9eNmmz'); + } + try { + // NOTE: Without the await here, the promise is returned immediately, + // and the catch block never fires. + return await api.handlePush({ refs, gitdir, remoteName, remoteUrl }); + } catch (error) { + console.error('api.handlePush threw #9Ei4c4'); + // console.error(error); + throw error; + } + } else if (command.command === GitCommands.fetch) { + const { refs } = command; + if (typeof api.handleFetch === 'undefined') { + throw new Error('api.handleFetch undefined #9eNmmz'); + } + try { + // NOTE: Without the await here, the promise is returned immediately, + // and the catch block never fires. + return await api.handleFetch({ refs, gitdir, remoteName, remoteUrl }); + } catch (error) { + console.error('api.handleFetch threw #5jxsQQ'); + // console.error(error); + throw error; + } + } + + throw new Error('Unrecognised command #e6nTnS'); + }, 1), + tap(x => { + logOutput('Sending response #31EyIs', JSON.stringify(x)); + }) + ); + + rxToStream(output).pipe(stdout); +}; + +export default GitRemoteHelper; \ No newline at end of file diff --git a/src/git/git.ts b/src/git/git.ts new file mode 100644 index 0000000..6025e24 --- /dev/null +++ b/src/git/git.ts @@ -0,0 +1,102 @@ +import { log } from './log'; +import { superpathjoin as join } from 'superpathjoin'; +import { ApiBaseParams } from './git-remote-helper'; +import { Storage } from '../storage/storage'; +class Git { + gitdir: string + remoteName: string + remoteUrl: string + storage: Storage + + constructor(info: ApiBaseParams, storage: Storage) { + this.gitdir = info.gitdir + this.remoteName = info.remoteName + this.remoteUrl = info.remoteUrl + this.storage = storage + } + + async do_list(forPush: boolean) { + let outLines: string[] = [] + let refs = this.get_refs(forPush) + for (let ref of refs) { + outLines.push(`${ref.sha} ${ref.ref}`) + } + if (!forPush) { + // head = self.read_symbolic_ref("HEAD") + // if head: + // _write("@%s HEAD" % head[1]) + // else: + // self._trace("no default branch on remote", Level.INFO) + // convert to typescript + + let head = await this.read_symbolic_ref("HEAD") + if (head) { + outLines.push(`@${head[1]} HEAD`) + } else { + log("no default branch on remote") + } + } + return "" + } + + async read_symbolic_ref(path: string) { + path = join(this.gitdir, path) + log("fetching symbolic ref: ", path) + + try { + // const [status, resp] = await this.storage.download(path); + // let ref = resp.content.toString("utf8"); + // ref = ref.slice("ref: ".length).trim(); + // const rev = meta.rev; + return []; + } catch (e) { + return null; + } + } + + get_refs(forPush: boolean): { sha: string, ref: string }[] { + // try { + // const loc = join(this.gitdir, "refs") + // let res = this._connection.files_list_folder(loc, recursive = true) + // let files = res.entries; + // while (res.has_more) { + // res = this._connection.files_list_folder_continue(res.cursor); + // files.extend(res.entries); + // } + // } catch (e) { + // if (e instanceof Error) { + // throw e; + // } + // if (forPush) { + // // this._first_push = true; + // } else { + // log("repository is empty") + // } + // return []; + // } + // files = files.filter((i) => i instanceof dropbox.files.FileMetadata); + // const paths = files.map((i) => i.path_lower); + // if (!paths.length) { + // return []; + // } + // let revs: string[] = []; + // let data: Uint8Array[] = []; + // for (let [rev, datum] of this._get_files(paths)) { + // revs.push(rev); + // data.push(datum); + // } + // const refs = []; + // for (let [path, rev, datum] of zip(paths, revs, data)) { + // const name = this._ref_name_from_path(path); + // const sha = datum.decode("utf8").strip(); + // this._refs[name] = [rev, sha]; + // refs.push([sha, name]); + // } + // return refs; + + return [] + } + +} + +export default Git \ No newline at end of file diff --git a/src/git/log.ts b/src/git/log.ts new file mode 100644 index 0000000..bf7e189 --- /dev/null +++ b/src/git/log.ts @@ -0,0 +1,6 @@ + + + +export const log = (...msg: any[]) => { + console.error(...msg) +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 84c649a..412e1a0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,14 @@ -import GitRemoteHelper from 'git-remote-helper'; -import debug from 'debug'; -const log = debug('git3'); -debug.enable('git3'); +import GitRemoteHelper from './git/git-remote-helper'; +import { ApiBaseParams } from './git/git-remote-helper'; +import Git from './git/git'; +import { log } from './git/log'; +import { ETHStorage } from './storage/ETHStorage'; + + + +let git: Git; GitRemoteHelper({ env: process.env, stdin: process.stdin, @@ -12,12 +17,8 @@ GitRemoteHelper({ /** * This will always be invoked when the remote helper is invoked */ - init: async (p: { - gitdir: string - remoteName: string - remoteUrl: string - }) => { - log('initlog', p); + init: async (p: ApiBaseParams) => { + git = new Git(p, new ETHStorage(p.remoteUrl)) return }, /** @@ -30,10 +31,7 @@ GitRemoteHelper({ forPush: boolean; }) => { log('list log', p) - // 相同 HEAD - return 'dbeac55f31922c90d34f9e57cc709c2c306c7e2e refs/heads/master\n\n'; - // 不同 HEAD - return 'dbeac55f31922c90d34f9e57cc709c2c306c7e2f refs/heads/master\n\n'; + return await git.do_list(p.forPush) }, /** * This should put the requested objects into the `.git` @@ -59,7 +57,7 @@ GitRemoteHelper({ force: boolean; }[]; }) => { - + log("push", p) return '\n'; }, @@ -67,5 +65,5 @@ GitRemoteHelper({ }).catch((error: any) => { console.error("wtf"); console.error(error); - + }); \ No newline at end of file diff --git a/src/storage/ETHStorage.ts b/src/storage/ETHStorage.ts new file mode 100644 index 0000000..fbe0d8e --- /dev/null +++ b/src/storage/ETHStorage.ts @@ -0,0 +1,37 @@ +import { Level } from "level"; +import { Ref, Status, Storage } from "./storage"; +const db = new Level('mock') + +export class ETHStorage implements Storage { + repoURI: string; + + constructor(repoURI: string) { + this.repoURI = repoURI + } + + listRefs(): Promise { + throw new Error("Method not implemented."); + } + addRefs(refs: Ref[]): Promise { + throw new Error("Method not implemented."); + } + delRefs(refs: Ref[]): Promise { + throw new Error("Method not implemented."); + } + + async delete(path: string): Promise { + throw new Error("Method not implemented."); + } + async download(path: string): Promise<[Status, Buffer]> { + const prefix = "file:" + let value = await db.get(prefix + path) + return [Status.SUCCEED, Buffer.from(value)] + } + + + async upload(path: string, file: Buffer): Promise { + const prefix = "file:" + await db.put(prefix + path, file.toString()) + return Status.SUCCEED + } +} diff --git a/src/storage/storage.ts b/src/storage/storage.ts new file mode 100644 index 0000000..5077d45 --- /dev/null +++ b/src/storage/storage.ts @@ -0,0 +1,24 @@ + +export enum Status { + SUCCEED = "SUCCEED", + TIMEOUT = "TIMEOUT", + FAILED = "FAILED", +} + +export type Ref = { + ref: string + sha: string + +} + +export interface Storage { + repoURI: string + + download(path: string): Promise<[Status, Buffer]> + upload(path: string, file: Buffer): Promise + delete(path: string): Promise + listRefs(): Promise + addRefs(refs: Ref[]): Promise + delRefs(refs: Ref[]): Promise + +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index cfb96a3..a847f21 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4,24 +4,24 @@ "@cspotcode/source-map-support@^0.8.0": version "0.8.1" - resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== dependencies: "@jridgewell/trace-mapping" "0.3.9" "@jridgewell/resolve-uri@^3.0.3": version "3.1.0" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.14" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== dependencies: "@jridgewell/resolve-uri" "^3.0.3" @@ -29,120 +29,220 @@ "@tsconfig/node10@^1.0.7": version "1.0.9" - resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== "@tsconfig/node12@^1.0.7": version "1.0.11" - resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== "@tsconfig/node14@^1.0.0": version "1.0.3" - resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== "@tsconfig/node16@^1.0.2": version "1.0.3" - resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== "@types/debug@^4.1.7": version "4.1.7" - resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg== dependencies: "@types/ms" "*" "@types/ms@*": version "0.7.31" - resolved "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== "@types/node@^18.11.10": - version "18.11.10" - resolved "https://registry.npmjs.org/@types/node/-/node-18.11.10.tgz" - integrity sha512-juG3RWMBOqcOuXC643OAdSA525V44cVgGV6dUDuiFtss+8Fk5x1hI93Rsld43VeJVIeqlP9I7Fn9/qaVqoEAuQ== + version "18.11.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.11.tgz#1d455ac0211549a8409d3cdb371cd55cc971e8dc" + integrity sha512-KJ021B1nlQUBLopzZmPBVuGU9un7WJd/W4ya7Ih02B4Uwky5Nja0yGYav2EfYIk0RR2Q9oVhf60S2XR1BCWJ2g== + +abstract-level@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.3.tgz#78a67d3d84da55ee15201486ab44c09560070741" + integrity sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA== + dependencies: + buffer "^6.0.3" + catering "^2.1.0" + is-buffer "^2.0.5" + level-supports "^4.0.0" + level-transcoder "^1.0.1" + module-error "^1.0.1" + queue-microtask "^1.2.3" acorn-walk@^8.1.1: version "8.2.0" - resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== acorn@^8.4.1: version "8.8.1" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73" integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== arg@^4.1.0: version "4.1.3" - resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +browser-level@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browser-level/-/browser-level-1.0.1.tgz#36e8c3183d0fe1c405239792faaab5f315871011" + integrity sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ== + dependencies: + abstract-level "^1.0.2" + catering "^2.1.1" + module-error "^1.0.2" + run-parallel-limit "^1.1.0" + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +catering@^2.1.0, catering@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" + integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== + +classic-level@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.2.0.tgz#2d52bdec8e7a27f534e67fdeb890abef3e643c27" + integrity sha512-qw5B31ANxSluWz9xBzklRWTUAJ1SXIdaVKTVS7HcTGKOAmExx65Wo5BUICW+YGORe2FOUaDghoI9ZDxj82QcFg== + dependencies: + abstract-level "^1.0.2" + catering "^2.1.0" + module-error "^1.0.1" + napi-macros "~2.0.0" + node-gyp-build "^4.3.0" + create-require@^1.1.0: version "1.1.1" - resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== debug@^4.3.4: version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" diff@^4.0.1: version "4.0.2" - resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -git-remote-helper@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/git-remote-helper/-/git-remote-helper-0.4.0.tgz" - integrity sha512-/+9pzNIdpZaaJ7HTNyfqzKhGY3sOjtPPdr3amceLvZLtWOcQ3TyPLaZU1N45ryUK2LdJcLCYlWw/tiTcOkMVkA== +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +is-buffer@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + +level-supports@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" + integrity sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== + +level-transcoder@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/level-transcoder/-/level-transcoder-1.0.1.tgz#f8cef5990c4f1283d4c86d949e73631b0bc8ba9c" + integrity sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w== dependencies: - rxjs "^6.6.3" - rxjs-async-map "^0.2.0" - rxjs-stream "^3.2.1" - superpathjoin "^2.0.1" + buffer "^6.0.3" + module-error "^1.0.1" + +level@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/level/-/level-8.0.0.tgz#41b4c515dabe28212a3e881b61c161ffead14394" + integrity sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ== + dependencies: + browser-level "^1.0.1" + classic-level "^1.2.0" make-error@^1.1.1: version "1.3.6" - resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +module-error@^1.0.1, module-error@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" + integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== + ms@2.1.2: version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +napi-macros@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" + integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== + +node-gyp-build@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" + integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== + +queue-microtask@^1.2.2, queue-microtask@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +run-parallel-limit@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz#be80e936f5768623a38a963262d6bef8ff11e7ba" + integrity sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw== + dependencies: + queue-microtask "^1.2.2" + rxjs-async-map@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/rxjs-async-map/-/rxjs-async-map-0.2.0.tgz" + resolved "https://registry.yarnpkg.com/rxjs-async-map/-/rxjs-async-map-0.2.0.tgz#5af3d069e85983602afb8f2091bc67bcc4306ac6" integrity sha512-HG1Hym+v0HXSZFkgFQmAxnCsraFc5zTjYp7YnCtgoNh+jYf08XpBR3dvi/zvTf17KylhRgmGuVzv/CpEbbWIgw== dependencies: rxjs "^6.3.3" rxjs-stream@^3.2.1: version "3.3.0" - resolved "https://registry.npmjs.org/rxjs-stream/-/rxjs-stream-3.3.0.tgz" + resolved "https://registry.yarnpkg.com/rxjs-stream/-/rxjs-stream-3.3.0.tgz#5fbc21fbd809ba6d27807d293518e1742154d51a" integrity sha512-Btxm8WUsvvAaQHS/iCcoYqQtezEzz5M4hTb0d1H6Oc+h0Xx/evpy0hWeo+YPQd2GhpmJkDaIoXbAyVh4hA4cRA== rxjs@^6.3.3, rxjs@^6.6.3: version "6.6.7" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== dependencies: tslib "^1.9.0" superpathjoin@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/superpathjoin/-/superpathjoin-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/superpathjoin/-/superpathjoin-2.0.1.tgz#57fdbad89a88a12f27635230d7fb0e66313bc233" integrity sha512-SvRdCHwKZEzjlM//VMBZYWmeu23NRtw5O29aBWDxEt4nD5GaWuRf9kmJuxmL8LfYMv+W+b/XhtU+7zFiaF6WAQ== ts-node@^10.9.1: version "10.9.1" - resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== dependencies: "@cspotcode/source-map-support" "^0.8.0" @@ -161,20 +261,20 @@ ts-node@^10.9.1: tslib@^1.9.0: version "1.14.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== typescript@^4.9.3: version "4.9.3" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db" integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA== v8-compile-cache-lib@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== yn@3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==