├── .gitignore ├── LICENSE.md ├── dist ├── collectionReference.d.ts ├── collectionReference.js ├── database.d.ts ├── database.js ├── documentReference.d.ts ├── documentReference.js ├── index.d.ts ├── index.js ├── pubsub.d.ts ├── pubsub.js ├── query.d.ts ├── query.js ├── types.d.ts └── types.js ├── package.json ├── readme.md ├── src ├── collectionReference.ts ├── database.ts ├── documentReference.ts ├── index.ts ├── pubsub.ts ├── query.ts └── types.ts ├── test └── test.mjs ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | sqlite.db -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2023 thenorthbay 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /dist/collectionReference.d.ts: -------------------------------------------------------------------------------- 1 | import { Database } from "./database"; 2 | import { DocumentReference } from "./documentReference"; 3 | import { Query } from "./query"; 4 | export declare class CollectionReference { 5 | private db; 6 | private collectionName; 7 | constructor(db: Database, collectionName: string); 8 | doc(docId?: string): DocumentReference; 9 | where(property: string, value: string): Query; 10 | } 11 | -------------------------------------------------------------------------------- /dist/collectionReference.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.CollectionReference = void 0; 4 | const crypto_1 = require("crypto"); 5 | const documentReference_1 = require("./documentReference"); 6 | const query_1 = require("./query"); 7 | class CollectionReference { 8 | constructor(db, collectionName) { 9 | this.db = db; 10 | this.collectionName = collectionName; 11 | } 12 | doc(docId) { 13 | if (!docId) 14 | return new documentReference_1.DocumentReference(this.db, this.collectionName, (0, crypto_1.randomUUID)()); 15 | return new documentReference_1.DocumentReference(this.db, this.collectionName, docId); 16 | } 17 | where(property, value) { 18 | // Create a Query object and return it 19 | return new query_1.Query(this.db, this.collectionName, property, value); 20 | } 21 | } 22 | exports.CollectionReference = CollectionReference; 23 | -------------------------------------------------------------------------------- /dist/database.d.ts: -------------------------------------------------------------------------------- 1 | import { CollectionReference } from "./collectionReference"; 2 | import { MessageFn } from "./pubsub"; 3 | import { ChangeEvent, Collection, JsonStoreValue, UnSubFn } from "./types"; 4 | export declare class Database { 5 | private db; 6 | private pubSub; 7 | constructor(); 8 | private connectToDatabase; 9 | private getDb; 10 | listen(type: "change", fn: MessageFn): UnSubFn; 11 | collection(collectionName: string): CollectionReference; 12 | addDoc(collection: Collection, doc: JsonStoreValue): Promise; 13 | updateDoc(collection: Collection, newVals: JsonStoreValue): Promise; 14 | private updateExistingDoc; 15 | deleteDoc(collection: Collection, docId: string): Promise; 16 | getDoc(collection: Collection, docId: string): Promise; 17 | getRowId(collection: Collection, docId: string): Promise; 18 | private getRowIdFromCollection; 19 | getDocs(collection: Collection, propertyFilter: string, propertyValue: string): Promise; 20 | private filterDocsByProperty; 21 | private createCollection; 22 | private createNewDoc; 23 | private getDocFromCollection; 24 | } 25 | -------------------------------------------------------------------------------- /dist/database.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.Database = void 0; 13 | const sqlite_1 = require("sqlite"); 14 | const collectionReference_1 = require("./collectionReference"); 15 | const pubsub_1 = require("./pubsub"); 16 | // core functionalities 17 | // 1. Get a doc from a collection by any property on the doc 18 | // 2. Get all docs from a collection by any property on the doc 19 | // 3. Set a doc to a collection (Create or update) 20 | // 4. Delete a doc from a collection 21 | // 5. Listen to changes to a doc / multiple docs in a collection (get entire doc for every change) 22 | // 6. Advantage: don't have to do indexes for subcollections. 23 | class Database { 24 | constructor() { 25 | this.db = null; 26 | this.pubSub = (0, pubsub_1.PubSub)(); 27 | } 28 | connectToDatabase(filename = "sqlite.db") { 29 | return __awaiter(this, void 0, void 0, function* () { 30 | const sqlite3 = require("sqlite3").verbose(); 31 | // open 32 | const db = yield (0, sqlite_1.open)({ 33 | filename: filename, 34 | driver: sqlite3.Database, 35 | }); 36 | return db; 37 | }); 38 | } 39 | // connect to DB 40 | getDb() { 41 | return __awaiter(this, void 0, void 0, function* () { 42 | if (!this.db) { 43 | const db = yield this.connectToDatabase(); 44 | // set 45 | this.db = db; 46 | // listen 47 | // this.db.on("profile", (sql: string) => { 48 | // this.pubSub.publish("profile", sql); 49 | // }); 50 | this.db.on("change", (eventType, database, table, rowId) => { 51 | const changeEvent = { 52 | eventType, 53 | database, 54 | table, 55 | rowId, 56 | }; 57 | this.pubSub.publish("change", changeEvent); 58 | }); 59 | return db; 60 | } 61 | return this.db; 62 | }); 63 | } 64 | listen(type, fn) { 65 | this.pubSub.subscribe(type, fn); 66 | return () => this.pubSub.unsubscribe(type, fn); 67 | } 68 | collection(collectionName) { 69 | return new collectionReference_1.CollectionReference(this, collectionName); 70 | } 71 | // set Doc to DB 72 | addDoc(collection, doc) { 73 | return __awaiter(this, void 0, void 0, function* () { 74 | const db = yield this.getDb(); 75 | try { 76 | yield this.createNewDoc(db, collection, doc); 77 | } 78 | catch (e) { 79 | console.log("error", e); 80 | return false; 81 | } 82 | return true; 83 | }); 84 | } 85 | updateDoc(collection, newVals) { 86 | return __awaiter(this, void 0, void 0, function* () { 87 | const db = yield this.getDb(); 88 | try { 89 | yield this.updateExistingDoc(db, collection, newVals); 90 | } 91 | catch (e) { 92 | console.log("error", e); 93 | return false; 94 | } 95 | return true; 96 | }); 97 | } 98 | updateExistingDoc(db, collection, newVals) { 99 | return __awaiter(this, void 0, void 0, function* () { 100 | if (!db) 101 | return; 102 | const partialQuery = `UPDATE ${collection} SET value = (json(?)) WHERE id == ?`; 103 | yield db.run(partialQuery, [JSON.stringify(newVals), newVals.id]); 104 | }); 105 | } 106 | deleteDoc(collection, docId) { 107 | return __awaiter(this, void 0, void 0, function* () { 108 | const db = yield this.getDb(); 109 | if (!db) 110 | return; 111 | const partialQuery = `DELETE FROM ${collection} WHERE id == ?`; 112 | yield db.run(partialQuery, [docId]); 113 | }); 114 | } 115 | // get doc from DB 116 | getDoc(collection, docId) { 117 | return __awaiter(this, void 0, void 0, function* () { 118 | const db = yield this.getDb(); 119 | const value = yield this.getDocFromCollection(db, collection, docId); 120 | return value; 121 | }); 122 | } 123 | getRowId(collection, docId) { 124 | return __awaiter(this, void 0, void 0, function* () { 125 | const db = yield this.getDb(); 126 | const rowId = yield this.getRowIdFromCollection(db, collection, docId); 127 | return rowId; 128 | }); 129 | } 130 | getRowIdFromCollection(db, collection, docId) { 131 | return __awaiter(this, void 0, void 0, function* () { 132 | if (!db) 133 | return; 134 | const partialQuery = `SELECT rowid FROM ${collection} WHERE id == ?`; 135 | const data = yield db.get(partialQuery, [docId]); 136 | return (data === null || data === void 0 ? void 0 : data.rowid) || null; 137 | }); 138 | } 139 | getDocs(collection, propertyFilter, propertyValue) { 140 | return __awaiter(this, void 0, void 0, function* () { 141 | const db = yield this.getDb(); 142 | const docs = yield this.filterDocsByProperty(db, collection, propertyFilter, propertyValue); 143 | return docs; 144 | }); 145 | } 146 | filterDocsByProperty(db, collection, property, propertyValue) { 147 | return __awaiter(this, void 0, void 0, function* () { 148 | if (!db) 149 | return; 150 | const partialQuery = `SELECT * FROM ${collection} WHERE json_extract(value, "$.${property}") == ?`; 151 | const rows = yield db.all(partialQuery, [propertyValue]); 152 | const docs = rows === null || rows === void 0 ? void 0 : rows.map((row) => JSON.parse(row.value)); 153 | return docs; 154 | }); 155 | } 156 | createCollection(db, collection) { 157 | return __awaiter(this, void 0, void 0, function* () { 158 | if (!db) 159 | return; 160 | const partialQuery = `CREATE TABLE IF NOT EXISTS ${collection} ( 161 | value TEXT, 162 | id TEXT GENERATED ALWAYS AS (json_extract(value, "$.id")) VIRTUAL NOT NULL)`; 163 | yield db.exec(partialQuery); 164 | }); 165 | } 166 | // function to insert something into the JSON database 167 | createNewDoc(db, collection, doc) { 168 | return __awaiter(this, void 0, void 0, function* () { 169 | if (!db) 170 | return; 171 | yield this.createCollection(db, collection); 172 | const partialQuery = `INSERT INTO ${collection} VALUES (json(?))`; 173 | const JSONdoc = JSON.stringify(doc); // convert the value to a JSON string 174 | yield db.run(partialQuery, [JSONdoc]); 175 | }); 176 | } 177 | // function to get the value of a key 178 | getDocFromCollection(db, collection, docId) { 179 | return __awaiter(this, void 0, void 0, function* () { 180 | if (!db) 181 | return null; 182 | const partialQuery = `SELECT value FROM ${collection} WHERE id = ?`; 183 | const row = yield db.get(partialQuery, [docId]); 184 | if (!row) { 185 | return null; 186 | } 187 | const value = JSON.parse(row.value); // convert the JSON string back to an object 188 | return value; 189 | }); 190 | } 191 | } 192 | exports.Database = Database; 193 | -------------------------------------------------------------------------------- /dist/documentReference.d.ts: -------------------------------------------------------------------------------- 1 | import { Database } from "./database"; 2 | import { JsonStoreValue } from "./types"; 3 | type SetOptions = { 4 | merge: boolean; 5 | }; 6 | export declare class DocumentReference { 7 | private db; 8 | private collectionName; 9 | private docId; 10 | constructor(db: Database, collectionName: string, docId: string); 11 | get(): Promise; 12 | getRowId(): Promise; 13 | set(docData: JsonStoreValue, options?: SetOptions): Promise; 14 | delete(): Promise; 15 | onSnapshot(onNext: (snapshot: JsonStoreValue | null) => void): import("./types").UnSubFn; 16 | } 17 | export {}; 18 | -------------------------------------------------------------------------------- /dist/documentReference.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.DocumentReference = void 0; 13 | class DocumentReference { 14 | constructor(db, collectionName, docId) { 15 | this.db = db; 16 | this.collectionName = collectionName; 17 | this.docId = docId; 18 | } 19 | get() { 20 | return __awaiter(this, void 0, void 0, function* () { 21 | const doc = yield this.db.getDoc(this.collectionName, this.docId); 22 | return doc; 23 | }); 24 | } 25 | getRowId() { 26 | return __awaiter(this, void 0, void 0, function* () { 27 | const rowId = yield this.db.getRowId(this.collectionName, this.docId); 28 | return rowId; 29 | }); 30 | } 31 | set(docData, options = { merge: false }) { 32 | return __awaiter(this, void 0, void 0, function* () { 33 | const existingDoc = yield this.get(); 34 | if (existingDoc) { 35 | if (options === null || options === void 0 ? void 0 : options.merge) { 36 | yield this.db.updateDoc(this.collectionName, Object.assign(Object.assign(Object.assign({}, existingDoc), docData), { id: this.docId })); 37 | } 38 | else { 39 | yield this.db.updateDoc(this.collectionName, Object.assign(Object.assign({}, docData), { id: this.docId })); 40 | } 41 | } 42 | else { 43 | yield this.db.addDoc(this.collectionName, Object.assign(Object.assign({}, docData), { id: this.docId })); 44 | } 45 | }); 46 | } 47 | delete() { 48 | return __awaiter(this, void 0, void 0, function* () { 49 | yield this.db.deleteDoc(this.collectionName, this.docId); 50 | }); 51 | } 52 | onSnapshot(onNext) { 53 | return this.db.listen("change", (args) => { 54 | this.getRowId().then((rowId) => { 55 | if (args.table == this.collectionName && args.rowId == rowId) { 56 | this.get().then(onNext); 57 | } 58 | }); 59 | }); 60 | } 61 | } 62 | exports.DocumentReference = DocumentReference; 63 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | export { Database } from "./database"; 2 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.Database = void 0; 4 | var database_1 = require("./database"); 5 | Object.defineProperty(exports, "Database", { enumerable: true, get: function () { return database_1.Database; } }); 6 | -------------------------------------------------------------------------------- /dist/pubsub.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Defines the function type of the publish function. 3 | * 4 | * Extracts the keys from `E` as valid event types, and the matching 5 | * property as the payload. 6 | */ 7 | type PubTypeFn = (event: Key, message: E[Key]) => void; 8 | /** 9 | * Defines the function type for the subscribe function. 10 | * 11 | * Extracts the keys from `E` as valid event types, and the matching 12 | * property as the payload to the callback function. 13 | */ 14 | type SubTypeFn = (event: Key, fn: MessageFn) => void; 15 | /** 16 | * Defines the function type for the subscription callback. Ensures 17 | * the message payload is a valid property of the event being used. 18 | */ 19 | export type MessageFn = (message: T) => void; 20 | /** 21 | * Tie everything together. 22 | */ 23 | type PubSubType = { 24 | publish: PubTypeFn; 25 | subscribe: SubTypeFn; 26 | unsubscribe: SubTypeFn; 27 | }; 28 | /** 29 | * Creates a new PubSub instance, the `E` type parameter should be a 30 | * type enumerating all the available events and their payloads. 31 | * 32 | * @example 33 | * type Events = { 34 | * warn: { message: string }, 35 | * error: { message: string } 36 | * } 37 | * 38 | * const pubSub = PubSub() 39 | * pubSub.publish('warn', { message: "Something bad happened!" }) 40 | */ 41 | export declare function PubSub(): PubSubType; 42 | export {}; 43 | -------------------------------------------------------------------------------- /dist/pubsub.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.PubSub = void 0; 4 | /** 5 | * Creates a new PubSub instance, the `E` type parameter should be a 6 | * type enumerating all the available events and their payloads. 7 | * 8 | * @example 9 | * type Events = { 10 | * warn: { message: string }, 11 | * error: { message: string } 12 | * } 13 | * 14 | * const pubSub = PubSub() 15 | * pubSub.publish('warn', { message: "Something bad happened!" }) 16 | */ 17 | function PubSub() { 18 | const handlers = {}; 19 | return { 20 | publish: (event, msg) => { 21 | var _a; 22 | (_a = handlers[event]) === null || _a === void 0 ? void 0 : _a.forEach((h) => h(msg)); 23 | }, 24 | subscribe: (event, callback) => { 25 | var _a; 26 | const list = (_a = handlers[event]) !== null && _a !== void 0 ? _a : []; 27 | list.push(callback); 28 | handlers[event] = list; 29 | }, 30 | unsubscribe: (event, callback) => { 31 | var _a; 32 | let list = (_a = handlers[event]) !== null && _a !== void 0 ? _a : []; 33 | list = list.filter((h) => h !== callback); 34 | handlers[event] = list; 35 | }, 36 | }; 37 | } 38 | exports.PubSub = PubSub; 39 | // EXAMPLE USAGE 40 | // type events = { 41 | // CreatedPerson: { id: string; name: string }; 42 | // DeletedPerson: { personId: string; reason: string }; 43 | // }; 44 | // const pubSub = PubSub(); 45 | // pubSub.publish("CreatedPerson", { id: "1", name: "cory" }); 46 | // pubSub.subscribe("CreatedPerson", (message) => { 47 | // console.log(message); 48 | // }); 49 | -------------------------------------------------------------------------------- /dist/query.d.ts: -------------------------------------------------------------------------------- 1 | import { Database } from "./database"; 2 | export declare class Query { 3 | private db; 4 | private collectionName; 5 | private property; 6 | private propertyValue; 7 | constructor(db: Database, collectionName: string, property: string, propertyValue: string); 8 | get(): Promise; 9 | onSnapshot(onNext: (docs: any[] | undefined) => void): import("./types").UnSubFn; 10 | } 11 | -------------------------------------------------------------------------------- /dist/query.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.Query = void 0; 13 | class Query { 14 | constructor(db, collectionName, property, propertyValue) { 15 | this.db = db; 16 | this.collectionName = collectionName; 17 | this.property = property; 18 | this.propertyValue = propertyValue; 19 | } 20 | get() { 21 | return __awaiter(this, void 0, void 0, function* () { 22 | const docs = yield this.db.getDocs(this.collectionName, this.property, this.propertyValue); 23 | return docs; 24 | }); 25 | } 26 | onSnapshot(onNext) { 27 | return this.db.listen("change", (args) => { 28 | if (args.table == this.collectionName) { 29 | this.get().then(onNext); 30 | } 31 | }); 32 | } 33 | } 34 | exports.Query = Query; 35 | -------------------------------------------------------------------------------- /dist/types.d.ts: -------------------------------------------------------------------------------- 1 | export interface ChangeEvent { 2 | eventType: string; 3 | database: string; 4 | table: string; 5 | rowId: string; 6 | } 7 | export type Collection = string; 8 | export type SQL = string; 9 | export type Events = { 10 | change: ChangeEvent; 11 | profile: SQL; 12 | }; 13 | export type UnSubFn = () => void; 14 | export type EventType = keyof Events; 15 | export interface JsonStoreValue { 16 | [key: string]: any; 17 | } 18 | -------------------------------------------------------------------------------- /dist/types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "doculite", 3 | "version": "1.0.4", 4 | "main": "dist/index.js", 5 | "types": "dist/index.d.ts", 6 | "files": [ 7 | "/dist" 8 | ], 9 | "repository": "https://github.com/thenorthbay/doculite.git", 10 | "license": "MIT", 11 | "dependencies": { 12 | "sqlite": "^5.0.1", 13 | "sqlite3": "^5.1.6" 14 | }, 15 | "peerDependencies": { 16 | "sqlite": "^5.0.1", 17 | "sqlite3": "^5.1.6" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Doculite 2 | 3 | DocuLite lets you use SQLite like Firebase Firestore. It's written in Typescript and an adapter on top of sqlite3 and sqlite. It support listeners on documents, collections, and basic queries. Google Group for users to discuss issues, problems, feature requests: [Google Group](https://groups.google.com/g/doculite) 4 | 5 | This is early work, so please treat it appropriately. 6 | 7 | # Current features 8 | 9 | ## 1. Initialize a DB 10 | 11 | Example: 12 | 13 | ```javascript 14 | import { Database } from "doculite"; 15 | 16 | // Creates sqlite.db file in the cwd 17 | const db = new Database(); 18 | ``` 19 | 20 | ## 2. Create Collections and Set Documents 21 | 22 | Collections are created on first insertion of a document. They are represented by a SQLite Table. 23 | 24 | ```javascript 25 | // create ref to the doc. Doc ID optional. 26 | 27 | const usersRef = db.collection("users").doc("123"); 28 | const refWithoutId = db.collection("users").doc(); 29 | 30 | // Any valid Javascript object that can be parsed to valid JSON can be inserted as a document. 31 | 32 | await usersRef.set({ 33 | username: "John Doe", 34 | createdAt: "123", 35 | updatedAt: "123", 36 | }); 37 | await refWithoutId.set({ username: "Jane Doe" }); 38 | ``` 39 | 40 | ## 3. Get a particular document 41 | 42 | ```javascript 43 | // define ref 44 | const usersRef = db.collection("users").doc("123"); 45 | // get 46 | const user = await usersRef.get(); 47 | // print 48 | console.log(user); // prints { username: "John Doe" }; 49 | ``` 50 | 51 | ## 4. Update Documents in Collections 52 | 53 | ```javascript 54 | // ref 55 | const usersRef = db.collection("users").doc("123"); 56 | 57 | // Properties existing on both old and new object will be updated. 58 | // Properties only existing on the new object will be added. 59 | 60 | // If merge is false, properties only present on the old object will be deleted. 61 | // Merge is true by default 62 | 63 | await ref.set({ username: "DERP Doe", updatedAt: "345" }, { merge: true }); 64 | // document in DB is now { username: "DERP Doe", updatedAt: "345", createdAt: "123" } 65 | 66 | await ref.set({ username: "DERP Doe", updatedAt: "345" }, { merge: false }); 67 | // document in DB is now { username: "DERP Doe", updatedAt: "345" } 68 | ``` 69 | 70 | ## 5. Delete Documents in Collection 71 | 72 | ```javascript 73 | const db = new Database(); 74 | 75 | const ref = db.collection("users").doc("deletable"); 76 | 77 | await ref.set({ username: "deletableUsername", updatedAt: 123123 }); 78 | 79 | await ref.delete(); 80 | 81 | const doc = await ref.get(); 82 | 83 | console.log(doc); // prints null 84 | ``` 85 | 86 | ## 6. Listen to real-time updates of documents. 87 | 88 | ```javascript 89 | // ref to doc 90 | const ref = db.collection("users").doc("123"); 91 | 92 | // snapshot listener returns unsubscribe function 93 | const unsub = ref.onSnapshot((doc) => { 94 | console.log("Omg the user doc is updating!", doc?.username); 95 | }); 96 | 97 | await ref.set({ username: "SHEESH Doe", updatedAt: 2 }); 98 | // prints: `Omg the user doc is updating! SHEESH Doe` 99 | 100 | // unsub 101 | unsub(); 102 | ``` 103 | 104 | ## 7. Query Documents in a collection by equality comparison 105 | 106 | ```javascript 107 | const usersRef = db.collection("users"); 108 | 109 | await usersRef.doc().set({ username: "Doculite", updatedAt: 234 }); 110 | 111 | const query = usersRef.where("username", "Doculite"); 112 | 113 | const docs = await query.get(); 114 | 115 | const user = docs[0]; 116 | 117 | console.log(user.username); // prints `Doculite` 118 | ``` 119 | 120 | # Potential roadmap: 121 | 122 | 1. Better query-based system 123 | 2. Stability and speed updates 124 | 3. Delete collections 125 | 4. Subcollections 126 | 5. Listeners on queries / multiple documents 127 | 6. Queries with other comparison operators (<, >, >=, <=, contains, etc.) 128 | 7. Queries for multiple variables (without indexes, probably) 129 | 8. Queries with Full Text Search (without indexes, probably) 130 | -------------------------------------------------------------------------------- /src/collectionReference.ts: -------------------------------------------------------------------------------- 1 | import { randomUUID } from "crypto"; 2 | import { Database } from "./database"; 3 | import { DocumentReference } from "./documentReference"; 4 | import { Query } from "./query"; 5 | 6 | export class CollectionReference { 7 | private db: Database; 8 | private collectionName: string; 9 | 10 | constructor(db: Database, collectionName: string) { 11 | this.db = db; 12 | this.collectionName = collectionName; 13 | } 14 | 15 | public doc(docId?: string) { 16 | if (!docId) 17 | return new DocumentReference(this.db, this.collectionName, randomUUID()); 18 | return new DocumentReference(this.db, this.collectionName, docId); 19 | } 20 | 21 | public where(property: string, value: string) { 22 | // Create a Query object and return it 23 | return new Query(this.db, this.collectionName, property, value); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/database.ts: -------------------------------------------------------------------------------- 1 | import { Database as SQLDb, open } from "sqlite"; 2 | import { CollectionReference } from "./collectionReference"; 3 | import { MessageFn, PubSub } from "./pubsub"; 4 | import { 5 | ChangeEvent, 6 | Collection, 7 | Events, 8 | JsonStoreValue, 9 | UnSubFn, 10 | } from "./types"; 11 | 12 | // core functionalities 13 | // 1. Get a doc from a collection by any property on the doc 14 | // 2. Get all docs from a collection by any property on the doc 15 | // 3. Set a doc to a collection (Create or update) 16 | // 4. Delete a doc from a collection 17 | // 5. Listen to changes to a doc / multiple docs in a collection (get entire doc for every change) 18 | // 6. Advantage: don't have to do indexes for subcollections. 19 | 20 | export class Database { 21 | private db: SQLDb | null; 22 | private pubSub; 23 | 24 | constructor() { 25 | this.db = null; 26 | this.pubSub = PubSub(); 27 | } 28 | 29 | private async connectToDatabase( 30 | filename: string = "sqlite.db" 31 | ): Promise { 32 | const sqlite3 = require("sqlite3").verbose(); 33 | 34 | // open 35 | const db = await open({ 36 | filename: filename, 37 | driver: sqlite3.Database, 38 | }); 39 | 40 | return db; 41 | } 42 | 43 | // connect to DB 44 | private async getDb(): Promise { 45 | if (!this.db) { 46 | const db = await this.connectToDatabase(); 47 | // set 48 | this.db = db; 49 | // listen 50 | // this.db.on("profile", (sql: string) => { 51 | // this.pubSub.publish("profile", sql); 52 | // }); 53 | this.db.on( 54 | "change", 55 | (eventType: string, database: string, table: string, rowId: string) => { 56 | const changeEvent: ChangeEvent = { 57 | eventType, 58 | database, 59 | table, 60 | rowId, 61 | }; 62 | this.pubSub.publish("change", changeEvent); 63 | } 64 | ); 65 | 66 | return db; 67 | } 68 | 69 | return this.db; 70 | } 71 | 72 | public listen(type: "change", fn: MessageFn): UnSubFn { 73 | this.pubSub.subscribe(type, fn); 74 | return () => this.pubSub.unsubscribe(type, fn); 75 | } 76 | 77 | public collection(collectionName: string) { 78 | return new CollectionReference(this, collectionName); 79 | } 80 | 81 | // set Doc to DB 82 | public async addDoc( 83 | collection: Collection, 84 | doc: JsonStoreValue 85 | ): Promise { 86 | const db = await this.getDb(); 87 | 88 | try { 89 | await this.createNewDoc(db, collection, doc); 90 | } catch (e) { 91 | console.log("error", e); 92 | return false; 93 | } 94 | 95 | return true; 96 | } 97 | 98 | public async updateDoc( 99 | collection: Collection, 100 | newVals: JsonStoreValue 101 | ): Promise { 102 | const db = await this.getDb(); 103 | 104 | try { 105 | await this.updateExistingDoc(db, collection, newVals); 106 | } catch (e) { 107 | console.log("error", e); 108 | return false; 109 | } 110 | 111 | return true; 112 | } 113 | 114 | private async updateExistingDoc( 115 | db: SQLDb | null, 116 | collection: Collection, 117 | newVals: JsonStoreValue 118 | ) { 119 | if (!db) return; 120 | 121 | const partialQuery = `UPDATE ${collection} SET value = (json(?)) WHERE id == ?`; 122 | 123 | await db.run(partialQuery, [JSON.stringify(newVals), newVals.id]); 124 | } 125 | 126 | public async deleteDoc(collection: Collection, docId: string) { 127 | const db = await this.getDb(); 128 | 129 | if (!db) return; 130 | 131 | const partialQuery = `DELETE FROM ${collection} WHERE id == ?`; 132 | 133 | await db.run(partialQuery, [docId]); 134 | } 135 | 136 | // get doc from DB 137 | public async getDoc(collection: Collection, docId: string) { 138 | const db = await this.getDb(); 139 | 140 | const value = await this.getDocFromCollection(db, collection, docId); 141 | 142 | return value; 143 | } 144 | 145 | public async getRowId(collection: Collection, docId: string) { 146 | const db = await this.getDb(); 147 | 148 | const rowId = await this.getRowIdFromCollection(db, collection, docId); 149 | 150 | return rowId; 151 | } 152 | 153 | private async getRowIdFromCollection( 154 | db: SQLDb | null, 155 | collection: Collection, 156 | docId: string 157 | ) { 158 | if (!db) return; 159 | 160 | const partialQuery = `SELECT rowid FROM ${collection} WHERE id == ?`; 161 | 162 | const data = await db.get(partialQuery, [docId]); 163 | 164 | return data?.rowid || null; 165 | } 166 | 167 | public async getDocs( 168 | collection: Collection, 169 | propertyFilter: string, 170 | propertyValue: string 171 | ) { 172 | const db = await this.getDb(); 173 | 174 | const docs = await this.filterDocsByProperty( 175 | db, 176 | collection, 177 | propertyFilter, 178 | propertyValue 179 | ); 180 | 181 | return docs; 182 | } 183 | 184 | private async filterDocsByProperty( 185 | db: SQLDb | null, 186 | collection: Collection, 187 | property: string, 188 | propertyValue: string 189 | ) { 190 | if (!db) return; 191 | 192 | const partialQuery = `SELECT * FROM ${collection} WHERE json_extract(value, "$.${property}") == ?`; 193 | 194 | const rows = await db.all(partialQuery, [propertyValue]); 195 | 196 | const docs = rows?.map((row) => JSON.parse(row.value)); 197 | 198 | return docs; 199 | } 200 | 201 | private async createCollection(db: SQLDb | null, collection: Collection) { 202 | if (!db) return; 203 | 204 | const partialQuery = `CREATE TABLE IF NOT EXISTS ${collection} ( 205 | value TEXT, 206 | id TEXT GENERATED ALWAYS AS (json_extract(value, "$.id")) VIRTUAL NOT NULL)`; 207 | 208 | await db.exec(partialQuery); 209 | } 210 | 211 | // function to insert something into the JSON database 212 | private async createNewDoc( 213 | db: SQLDb | null, 214 | collection: Collection, 215 | doc: JsonStoreValue 216 | ): Promise { 217 | if (!db) return; 218 | 219 | await this.createCollection(db, collection); 220 | 221 | const partialQuery = `INSERT INTO ${collection} VALUES (json(?))`; 222 | 223 | const JSONdoc = JSON.stringify(doc); // convert the value to a JSON string 224 | await db.run(partialQuery, [JSONdoc]); 225 | } 226 | 227 | // function to get the value of a key 228 | private async getDocFromCollection( 229 | db: SQLDb | null, 230 | collection: Collection, 231 | docId: string 232 | ): Promise { 233 | if (!db) return null; 234 | 235 | const partialQuery = `SELECT value FROM ${collection} WHERE id = ?`; 236 | 237 | const row = await db.get(partialQuery, [docId]); 238 | 239 | if (!row) { 240 | return null; 241 | } 242 | 243 | const value = JSON.parse(row.value); // convert the JSON string back to an object 244 | return value; 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /src/documentReference.ts: -------------------------------------------------------------------------------- 1 | import { Database } from "./database"; 2 | import { ChangeEvent, JsonStoreValue } from "./types"; 3 | 4 | type SetOptions = { 5 | merge: boolean; 6 | }; 7 | 8 | export class DocumentReference { 9 | private db: Database; 10 | private collectionName: string; 11 | private docId: string; 12 | 13 | constructor(db: Database, collectionName: string, docId: string) { 14 | this.db = db; 15 | this.collectionName = collectionName; 16 | this.docId = docId; 17 | } 18 | 19 | public async get() { 20 | const doc = await this.db.getDoc(this.collectionName, this.docId); 21 | return doc; 22 | } 23 | 24 | public async getRowId() { 25 | const rowId = await this.db.getRowId(this.collectionName, this.docId); 26 | return rowId; 27 | } 28 | 29 | public async set( 30 | docData: JsonStoreValue, 31 | options: SetOptions = { merge: false } 32 | ) { 33 | const existingDoc = await this.get(); 34 | 35 | if (existingDoc) { 36 | if (options?.merge) { 37 | await this.db.updateDoc(this.collectionName, { 38 | ...existingDoc, 39 | ...docData, 40 | id: this.docId, 41 | }); 42 | } else { 43 | await this.db.updateDoc(this.collectionName, { 44 | ...docData, 45 | id: this.docId, 46 | }); 47 | } 48 | } else { 49 | await this.db.addDoc(this.collectionName, { ...docData, id: this.docId }); 50 | } 51 | } 52 | 53 | public async delete() { 54 | await this.db.deleteDoc(this.collectionName, this.docId); 55 | } 56 | 57 | public onSnapshot(onNext: (snapshot: JsonStoreValue | null) => void) { 58 | return this.db.listen("change", (args: ChangeEvent) => { 59 | this.getRowId().then((rowId) => { 60 | if (args.table == this.collectionName && args.rowId == rowId) { 61 | this.get().then(onNext); 62 | } 63 | }); 64 | }); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { Database } from "./database"; 2 | -------------------------------------------------------------------------------- /src/pubsub.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Defines the function type of the publish function. 3 | * 4 | * Extracts the keys from `E` as valid event types, and the matching 5 | * property as the payload. 6 | */ 7 | type PubTypeFn = ( 8 | event: Key, 9 | message: E[Key] 10 | ) => void; 11 | 12 | /** 13 | * Defines the function type for the subscribe function. 14 | * 15 | * Extracts the keys from `E` as valid event types, and the matching 16 | * property as the payload to the callback function. 17 | */ 18 | type SubTypeFn = ( 19 | event: Key, 20 | fn: MessageFn 21 | ) => void; 22 | 23 | /** 24 | * Defines the function type for the subscription callback. Ensures 25 | * the message payload is a valid property of the event being used. 26 | */ 27 | export type MessageFn = (message: T) => void; 28 | 29 | /** 30 | * Tie everything together. 31 | */ 32 | type PubSubType = { 33 | publish: PubTypeFn; 34 | subscribe: SubTypeFn; 35 | unsubscribe: SubTypeFn; 36 | }; 37 | 38 | /** 39 | * Creates a new PubSub instance, the `E` type parameter should be a 40 | * type enumerating all the available events and their payloads. 41 | * 42 | * @example 43 | * type Events = { 44 | * warn: { message: string }, 45 | * error: { message: string } 46 | * } 47 | * 48 | * const pubSub = PubSub() 49 | * pubSub.publish('warn', { message: "Something bad happened!" }) 50 | */ 51 | export function PubSub(): PubSubType { 52 | const handlers: { [key: string]: MessageFn[] } = {}; 53 | 54 | return { 55 | publish: (event, msg) => { 56 | handlers[event]?.forEach((h) => h(msg)); 57 | }, 58 | 59 | subscribe: (event, callback) => { 60 | const list = handlers[event] ?? []; 61 | list.push(callback); 62 | handlers[event] = list; 63 | }, 64 | 65 | unsubscribe: (event, callback) => { 66 | let list = handlers[event] ?? []; 67 | list = list.filter((h) => h !== callback); 68 | handlers[event] = list; 69 | }, 70 | }; 71 | } 72 | 73 | // EXAMPLE USAGE 74 | 75 | // type events = { 76 | // CreatedPerson: { id: string; name: string }; 77 | // DeletedPerson: { personId: string; reason: string }; 78 | // }; 79 | 80 | // const pubSub = PubSub(); 81 | 82 | // pubSub.publish("CreatedPerson", { id: "1", name: "cory" }); 83 | 84 | // pubSub.subscribe("CreatedPerson", (message) => { 85 | // console.log(message); 86 | // }); 87 | -------------------------------------------------------------------------------- /src/query.ts: -------------------------------------------------------------------------------- 1 | import { Database } from "./database"; 2 | import { ChangeEvent } from "./types"; 3 | 4 | export class Query { 5 | private db: Database; 6 | private collectionName: string; 7 | private property: string; 8 | private propertyValue: string; 9 | 10 | constructor( 11 | db: Database, 12 | collectionName: string, 13 | property: string, 14 | propertyValue: string 15 | ) { 16 | this.db = db; 17 | this.collectionName = collectionName; 18 | this.property = property; 19 | this.propertyValue = propertyValue; 20 | } 21 | 22 | public async get() { 23 | const docs = await this.db.getDocs( 24 | this.collectionName, 25 | this.property, 26 | this.propertyValue 27 | ); 28 | return docs; 29 | } 30 | 31 | public onSnapshot(onNext: (docs: any[] | undefined) => void) { 32 | return this.db.listen("change", (args: ChangeEvent) => { 33 | if (args.table == this.collectionName) { 34 | this.get().then(onNext); 35 | } 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export interface ChangeEvent { 2 | eventType: string; //"insert" 3 | database: string; // "main" 4 | table: string; // "wishlists" 5 | rowId: string; // position of doc in collection 6 | } 7 | 8 | export type Collection = string; 9 | export type SQL = string; 10 | export type Events = { 11 | change: ChangeEvent; 12 | profile: SQL; 13 | }; 14 | export type UnSubFn = () => void; 15 | export type EventType = keyof Events; 16 | 17 | export interface JsonStoreValue { 18 | [key: string]: any; 19 | } 20 | -------------------------------------------------------------------------------- /test/test.mjs: -------------------------------------------------------------------------------- 1 | import { describe, it } from "node:test"; 2 | import assert from "node:assert/strict"; 3 | 4 | import { Database } from "../dist/index.js"; 5 | 6 | // write a bunch o 7 | describe("listener", () => { 8 | it("should listen", async () => { 9 | const db = new Database(); 10 | 11 | const usersRef = db.collection("users").doc("123"); 12 | 13 | await usersRef.set({ username: "John Doe", updatedAt: 123123 }); 14 | 15 | const ref = db.collection("users").doc("123"); 16 | 17 | const unsub = ref.onSnapshot((doc) => { 18 | console.log("Omg the user doc is updating!", doc); 19 | assert.strictEqual(doc?.username, "JANE Doe"); 20 | }); 21 | 22 | await ref.set({ username: "JANE Doe", updatedAt: 1 }, { merge: false }); 23 | 24 | unsub(); 25 | }); 26 | }); 27 | describe("should delete", () => { 28 | it("should delete", async () => { 29 | const db = new Database(); 30 | 31 | const ref = db.collection("users").doc("deletable"); 32 | 33 | await ref.set({ username: "John Doe", updatedAt: 123123 }); 34 | 35 | await ref.delete(); 36 | 37 | const doc = await ref.get(); 38 | 39 | assert.strictEqual(doc, null); 40 | }); 41 | }); 42 | 43 | describe("query", () => { 44 | it("should query", async () => { 45 | const db = new Database(); 46 | 47 | const usersRef = db.collection("users"); 48 | 49 | await usersRef.doc().set({ username: "Doculite", updatedAt: 234 }); 50 | 51 | const query = usersRef.where("username", "Doculite"); 52 | 53 | const docs = await query.get(); 54 | 55 | assert.strictEqual(docs[0]?.username, "Doculite"); 56 | }); 57 | }); 58 | 59 | describe("docRef", () => { 60 | it("should get null if it doesn't exist!", async () => { 61 | const db = new Database(); 62 | const usersRef = db.collection("users").doc("22"); 63 | const user = await usersRef.get(); 64 | assert.strictEqual(user?.username, undefined); 65 | assert.strictEqual(user, null); 66 | }); 67 | it("should get an old doc", async () => { 68 | const db = new Database(); 69 | const usersRef = db.collection("users").doc("123"); 70 | const user = await usersRef.get(); 71 | assert.strictEqual(user?.username, "JANE Doe"); 72 | }); 73 | it("should get a doc", async () => { 74 | const db = new Database(); 75 | const usersRef = db.collection("users").doc("derp"); 76 | await usersRef.set({ 77 | username: "Johnny Derp", 78 | updatedAt: 123123, 79 | lit: true, 80 | }); 81 | const user = await usersRef.get(); 82 | assert.strictEqual(user?.username, "Johnny Derp"); 83 | assert.strictEqual(user?.lit, true); 84 | }); 85 | it("should be able to update the docc", async () => { 86 | const db = new Database(); 87 | const usersRef = db.collection("users").doc("derp"); 88 | await usersRef.set({ lit: false }); 89 | const user = await usersRef.get(); 90 | assert.strictEqual(user?.lit, false); 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2015", 5 | "declaration": true, 6 | "outDir": "./dist" 7 | }, 8 | "include": [ 9 | "./src/**/*" 10 | ] 11 | } -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@gar/promisify@^1.0.1": 6 | version "1.1.3" 7 | resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" 8 | integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== 9 | 10 | "@mapbox/node-pre-gyp@^1.0.0": 11 | version "1.0.11" 12 | resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa" 13 | integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ== 14 | dependencies: 15 | detect-libc "^2.0.0" 16 | https-proxy-agent "^5.0.0" 17 | make-dir "^3.1.0" 18 | node-fetch "^2.6.7" 19 | nopt "^5.0.0" 20 | npmlog "^5.0.1" 21 | rimraf "^3.0.2" 22 | semver "^7.3.5" 23 | tar "^6.1.11" 24 | 25 | "@npmcli/fs@^1.0.0": 26 | version "1.1.1" 27 | resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" 28 | integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ== 29 | dependencies: 30 | "@gar/promisify" "^1.0.1" 31 | semver "^7.3.5" 32 | 33 | "@npmcli/move-file@^1.0.1": 34 | version "1.1.2" 35 | resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" 36 | integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== 37 | dependencies: 38 | mkdirp "^1.0.4" 39 | rimraf "^3.0.2" 40 | 41 | "@tootallnate/once@1": 42 | version "1.1.2" 43 | resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" 44 | integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== 45 | 46 | abbrev@1: 47 | version "1.1.1" 48 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" 49 | integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== 50 | 51 | agent-base@6, agent-base@^6.0.2: 52 | version "6.0.2" 53 | resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" 54 | integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== 55 | dependencies: 56 | debug "4" 57 | 58 | agentkeepalive@^4.1.3: 59 | version "4.3.0" 60 | resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.3.0.tgz#bb999ff07412653c1803b3ced35e50729830a255" 61 | integrity sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg== 62 | dependencies: 63 | debug "^4.1.0" 64 | depd "^2.0.0" 65 | humanize-ms "^1.2.1" 66 | 67 | aggregate-error@^3.0.0: 68 | version "3.1.0" 69 | resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" 70 | integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== 71 | dependencies: 72 | clean-stack "^2.0.0" 73 | indent-string "^4.0.0" 74 | 75 | ansi-regex@^5.0.1: 76 | version "5.0.1" 77 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 78 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 79 | 80 | "aproba@^1.0.3 || ^2.0.0": 81 | version "2.0.0" 82 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" 83 | integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== 84 | 85 | are-we-there-yet@^2.0.0: 86 | version "2.0.0" 87 | resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" 88 | integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== 89 | dependencies: 90 | delegates "^1.0.0" 91 | readable-stream "^3.6.0" 92 | 93 | are-we-there-yet@^3.0.0: 94 | version "3.0.1" 95 | resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" 96 | integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== 97 | dependencies: 98 | delegates "^1.0.0" 99 | readable-stream "^3.6.0" 100 | 101 | balanced-match@^1.0.0: 102 | version "1.0.2" 103 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 104 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 105 | 106 | brace-expansion@^1.1.7: 107 | version "1.1.11" 108 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 109 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 110 | dependencies: 111 | balanced-match "^1.0.0" 112 | concat-map "0.0.1" 113 | 114 | cacache@^15.2.0: 115 | version "15.3.0" 116 | resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" 117 | integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== 118 | dependencies: 119 | "@npmcli/fs" "^1.0.0" 120 | "@npmcli/move-file" "^1.0.1" 121 | chownr "^2.0.0" 122 | fs-minipass "^2.0.0" 123 | glob "^7.1.4" 124 | infer-owner "^1.0.4" 125 | lru-cache "^6.0.0" 126 | minipass "^3.1.1" 127 | minipass-collect "^1.0.2" 128 | minipass-flush "^1.0.5" 129 | minipass-pipeline "^1.2.2" 130 | mkdirp "^1.0.3" 131 | p-map "^4.0.0" 132 | promise-inflight "^1.0.1" 133 | rimraf "^3.0.2" 134 | ssri "^8.0.1" 135 | tar "^6.0.2" 136 | unique-filename "^1.1.1" 137 | 138 | chownr@^2.0.0: 139 | version "2.0.0" 140 | resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" 141 | integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== 142 | 143 | clean-stack@^2.0.0: 144 | version "2.2.0" 145 | resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" 146 | integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== 147 | 148 | color-support@^1.1.2, color-support@^1.1.3: 149 | version "1.1.3" 150 | resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" 151 | integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== 152 | 153 | concat-map@0.0.1: 154 | version "0.0.1" 155 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 156 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 157 | 158 | console-control-strings@^1.0.0, console-control-strings@^1.1.0: 159 | version "1.1.0" 160 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 161 | integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== 162 | 163 | debug@4, debug@^4.1.0, debug@^4.3.3: 164 | version "4.3.4" 165 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" 166 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== 167 | dependencies: 168 | ms "2.1.2" 169 | 170 | delegates@^1.0.0: 171 | version "1.0.0" 172 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 173 | integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== 174 | 175 | depd@^2.0.0: 176 | version "2.0.0" 177 | resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" 178 | integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== 179 | 180 | detect-libc@^2.0.0: 181 | version "2.0.2" 182 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.2.tgz#8ccf2ba9315350e1241b88d0ac3b0e1fbd99605d" 183 | integrity sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw== 184 | 185 | emoji-regex@^8.0.0: 186 | version "8.0.0" 187 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 188 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 189 | 190 | encoding@^0.1.12: 191 | version "0.1.13" 192 | resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" 193 | integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== 194 | dependencies: 195 | iconv-lite "^0.6.2" 196 | 197 | env-paths@^2.2.0: 198 | version "2.2.1" 199 | resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" 200 | integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== 201 | 202 | err-code@^2.0.2: 203 | version "2.0.3" 204 | resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" 205 | integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== 206 | 207 | fs-minipass@^2.0.0: 208 | version "2.1.0" 209 | resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" 210 | integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== 211 | dependencies: 212 | minipass "^3.0.0" 213 | 214 | fs.realpath@^1.0.0: 215 | version "1.0.0" 216 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 217 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 218 | 219 | gauge@^3.0.0: 220 | version "3.0.2" 221 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" 222 | integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== 223 | dependencies: 224 | aproba "^1.0.3 || ^2.0.0" 225 | color-support "^1.1.2" 226 | console-control-strings "^1.0.0" 227 | has-unicode "^2.0.1" 228 | object-assign "^4.1.1" 229 | signal-exit "^3.0.0" 230 | string-width "^4.2.3" 231 | strip-ansi "^6.0.1" 232 | wide-align "^1.1.2" 233 | 234 | gauge@^4.0.3: 235 | version "4.0.4" 236 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" 237 | integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg== 238 | dependencies: 239 | aproba "^1.0.3 || ^2.0.0" 240 | color-support "^1.1.3" 241 | console-control-strings "^1.1.0" 242 | has-unicode "^2.0.1" 243 | signal-exit "^3.0.7" 244 | string-width "^4.2.3" 245 | strip-ansi "^6.0.1" 246 | wide-align "^1.1.5" 247 | 248 | glob@^7.1.3, glob@^7.1.4: 249 | version "7.2.3" 250 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 251 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 252 | dependencies: 253 | fs.realpath "^1.0.0" 254 | inflight "^1.0.4" 255 | inherits "2" 256 | minimatch "^3.1.1" 257 | once "^1.3.0" 258 | path-is-absolute "^1.0.0" 259 | 260 | graceful-fs@^4.2.6: 261 | version "4.2.11" 262 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" 263 | integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== 264 | 265 | has-unicode@^2.0.1: 266 | version "2.0.1" 267 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 268 | integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== 269 | 270 | http-cache-semantics@^4.1.0: 271 | version "4.1.1" 272 | resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" 273 | integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== 274 | 275 | http-proxy-agent@^4.0.1: 276 | version "4.0.1" 277 | resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" 278 | integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== 279 | dependencies: 280 | "@tootallnate/once" "1" 281 | agent-base "6" 282 | debug "4" 283 | 284 | https-proxy-agent@^5.0.0: 285 | version "5.0.1" 286 | resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" 287 | integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== 288 | dependencies: 289 | agent-base "6" 290 | debug "4" 291 | 292 | humanize-ms@^1.2.1: 293 | version "1.2.1" 294 | resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" 295 | integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== 296 | dependencies: 297 | ms "^2.0.0" 298 | 299 | iconv-lite@^0.6.2: 300 | version "0.6.3" 301 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" 302 | integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== 303 | dependencies: 304 | safer-buffer ">= 2.1.2 < 3.0.0" 305 | 306 | imurmurhash@^0.1.4: 307 | version "0.1.4" 308 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 309 | integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== 310 | 311 | indent-string@^4.0.0: 312 | version "4.0.0" 313 | resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" 314 | integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== 315 | 316 | infer-owner@^1.0.4: 317 | version "1.0.4" 318 | resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" 319 | integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== 320 | 321 | inflight@^1.0.4: 322 | version "1.0.6" 323 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 324 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 325 | dependencies: 326 | once "^1.3.0" 327 | wrappy "1" 328 | 329 | inherits@2, inherits@^2.0.3: 330 | version "2.0.4" 331 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 332 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 333 | 334 | ip@^2.0.0: 335 | version "2.0.0" 336 | resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" 337 | integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== 338 | 339 | is-fullwidth-code-point@^3.0.0: 340 | version "3.0.0" 341 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 342 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 343 | 344 | is-lambda@^1.0.1: 345 | version "1.0.1" 346 | resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" 347 | integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== 348 | 349 | isexe@^2.0.0: 350 | version "2.0.0" 351 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 352 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== 353 | 354 | lru-cache@^6.0.0: 355 | version "6.0.0" 356 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" 357 | integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== 358 | dependencies: 359 | yallist "^4.0.0" 360 | 361 | make-dir@^3.1.0: 362 | version "3.1.0" 363 | resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" 364 | integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== 365 | dependencies: 366 | semver "^6.0.0" 367 | 368 | make-fetch-happen@^9.1.0: 369 | version "9.1.0" 370 | resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" 371 | integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== 372 | dependencies: 373 | agentkeepalive "^4.1.3" 374 | cacache "^15.2.0" 375 | http-cache-semantics "^4.1.0" 376 | http-proxy-agent "^4.0.1" 377 | https-proxy-agent "^5.0.0" 378 | is-lambda "^1.0.1" 379 | lru-cache "^6.0.0" 380 | minipass "^3.1.3" 381 | minipass-collect "^1.0.2" 382 | minipass-fetch "^1.3.2" 383 | minipass-flush "^1.0.5" 384 | minipass-pipeline "^1.2.4" 385 | negotiator "^0.6.2" 386 | promise-retry "^2.0.1" 387 | socks-proxy-agent "^6.0.0" 388 | ssri "^8.0.0" 389 | 390 | minimatch@^3.1.1: 391 | version "3.1.2" 392 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 393 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 394 | dependencies: 395 | brace-expansion "^1.1.7" 396 | 397 | minipass-collect@^1.0.2: 398 | version "1.0.2" 399 | resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" 400 | integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== 401 | dependencies: 402 | minipass "^3.0.0" 403 | 404 | minipass-fetch@^1.3.2: 405 | version "1.4.1" 406 | resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" 407 | integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== 408 | dependencies: 409 | minipass "^3.1.0" 410 | minipass-sized "^1.0.3" 411 | minizlib "^2.0.0" 412 | optionalDependencies: 413 | encoding "^0.1.12" 414 | 415 | minipass-flush@^1.0.5: 416 | version "1.0.5" 417 | resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" 418 | integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== 419 | dependencies: 420 | minipass "^3.0.0" 421 | 422 | minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: 423 | version "1.2.4" 424 | resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" 425 | integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== 426 | dependencies: 427 | minipass "^3.0.0" 428 | 429 | minipass-sized@^1.0.3: 430 | version "1.0.3" 431 | resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" 432 | integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== 433 | dependencies: 434 | minipass "^3.0.0" 435 | 436 | minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: 437 | version "3.3.6" 438 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" 439 | integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== 440 | dependencies: 441 | yallist "^4.0.0" 442 | 443 | minipass@^5.0.0: 444 | version "5.0.0" 445 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" 446 | integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== 447 | 448 | minizlib@^2.0.0, minizlib@^2.1.1: 449 | version "2.1.2" 450 | resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" 451 | integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== 452 | dependencies: 453 | minipass "^3.0.0" 454 | yallist "^4.0.0" 455 | 456 | mkdirp@^1.0.3, mkdirp@^1.0.4: 457 | version "1.0.4" 458 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" 459 | integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== 460 | 461 | ms@2.1.2: 462 | version "2.1.2" 463 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 464 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 465 | 466 | ms@^2.0.0: 467 | version "2.1.3" 468 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 469 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 470 | 471 | negotiator@^0.6.2: 472 | version "0.6.3" 473 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" 474 | integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== 475 | 476 | node-addon-api@^4.2.0: 477 | version "4.3.0" 478 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f" 479 | integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ== 480 | 481 | node-fetch@^2.6.7: 482 | version "2.6.12" 483 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba" 484 | integrity sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g== 485 | dependencies: 486 | whatwg-url "^5.0.0" 487 | 488 | node-gyp@8.x: 489 | version "8.4.1" 490 | resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937" 491 | integrity sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w== 492 | dependencies: 493 | env-paths "^2.2.0" 494 | glob "^7.1.4" 495 | graceful-fs "^4.2.6" 496 | make-fetch-happen "^9.1.0" 497 | nopt "^5.0.0" 498 | npmlog "^6.0.0" 499 | rimraf "^3.0.2" 500 | semver "^7.3.5" 501 | tar "^6.1.2" 502 | which "^2.0.2" 503 | 504 | nopt@^5.0.0: 505 | version "5.0.0" 506 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" 507 | integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== 508 | dependencies: 509 | abbrev "1" 510 | 511 | npmlog@^5.0.1: 512 | version "5.0.1" 513 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" 514 | integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== 515 | dependencies: 516 | are-we-there-yet "^2.0.0" 517 | console-control-strings "^1.1.0" 518 | gauge "^3.0.0" 519 | set-blocking "^2.0.0" 520 | 521 | npmlog@^6.0.0: 522 | version "6.0.2" 523 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" 524 | integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== 525 | dependencies: 526 | are-we-there-yet "^3.0.0" 527 | console-control-strings "^1.1.0" 528 | gauge "^4.0.3" 529 | set-blocking "^2.0.0" 530 | 531 | object-assign@^4.1.1: 532 | version "4.1.1" 533 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 534 | integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== 535 | 536 | once@^1.3.0: 537 | version "1.4.0" 538 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 539 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 540 | dependencies: 541 | wrappy "1" 542 | 543 | p-map@^4.0.0: 544 | version "4.0.0" 545 | resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" 546 | integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== 547 | dependencies: 548 | aggregate-error "^3.0.0" 549 | 550 | path-is-absolute@^1.0.0: 551 | version "1.0.1" 552 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 553 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 554 | 555 | promise-inflight@^1.0.1: 556 | version "1.0.1" 557 | resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" 558 | integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== 559 | 560 | promise-retry@^2.0.1: 561 | version "2.0.1" 562 | resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" 563 | integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== 564 | dependencies: 565 | err-code "^2.0.2" 566 | retry "^0.12.0" 567 | 568 | readable-stream@^3.6.0: 569 | version "3.6.2" 570 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" 571 | integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== 572 | dependencies: 573 | inherits "^2.0.3" 574 | string_decoder "^1.1.1" 575 | util-deprecate "^1.0.1" 576 | 577 | retry@^0.12.0: 578 | version "0.12.0" 579 | resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" 580 | integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== 581 | 582 | rimraf@^3.0.2: 583 | version "3.0.2" 584 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 585 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 586 | dependencies: 587 | glob "^7.1.3" 588 | 589 | safe-buffer@~5.2.0: 590 | version "5.2.1" 591 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 592 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 593 | 594 | "safer-buffer@>= 2.1.2 < 3.0.0": 595 | version "2.1.2" 596 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 597 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 598 | 599 | semver@^6.0.0: 600 | version "6.3.1" 601 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" 602 | integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== 603 | 604 | semver@^7.3.5: 605 | version "7.5.4" 606 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" 607 | integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== 608 | dependencies: 609 | lru-cache "^6.0.0" 610 | 611 | set-blocking@^2.0.0: 612 | version "2.0.0" 613 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 614 | integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== 615 | 616 | signal-exit@^3.0.0, signal-exit@^3.0.7: 617 | version "3.0.7" 618 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" 619 | integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== 620 | 621 | smart-buffer@^4.2.0: 622 | version "4.2.0" 623 | resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" 624 | integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== 625 | 626 | socks-proxy-agent@^6.0.0: 627 | version "6.2.1" 628 | resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce" 629 | integrity sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ== 630 | dependencies: 631 | agent-base "^6.0.2" 632 | debug "^4.3.3" 633 | socks "^2.6.2" 634 | 635 | socks@^2.6.2: 636 | version "2.7.1" 637 | resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55" 638 | integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== 639 | dependencies: 640 | ip "^2.0.0" 641 | smart-buffer "^4.2.0" 642 | 643 | sqlite3@^5.1.6: 644 | version "5.1.6" 645 | resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.1.6.tgz#1d4fbc90fe4fbd51e952e0a90fd8f6c2b9098e97" 646 | integrity sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw== 647 | dependencies: 648 | "@mapbox/node-pre-gyp" "^1.0.0" 649 | node-addon-api "^4.2.0" 650 | tar "^6.1.11" 651 | optionalDependencies: 652 | node-gyp "8.x" 653 | 654 | sqlite@^5.0.1: 655 | version "5.0.1" 656 | resolved "https://registry.yarnpkg.com/sqlite/-/sqlite-5.0.1.tgz#4b0fcb1e13d665b073b9b53cb8357a1055f5c7ea" 657 | integrity sha512-sRxbVwzNX9rvEPnxz9scNqi60KtfxBXMzzus5BI4+0nPtVkyEXyBwQ7JkM2M1CiVvEFw6s1vn2Z9/1DEdSpiaA== 658 | 659 | ssri@^8.0.0, ssri@^8.0.1: 660 | version "8.0.1" 661 | resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" 662 | integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== 663 | dependencies: 664 | minipass "^3.1.1" 665 | 666 | "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3: 667 | version "4.2.3" 668 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 669 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 670 | dependencies: 671 | emoji-regex "^8.0.0" 672 | is-fullwidth-code-point "^3.0.0" 673 | strip-ansi "^6.0.1" 674 | 675 | string_decoder@^1.1.1: 676 | version "1.3.0" 677 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" 678 | integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== 679 | dependencies: 680 | safe-buffer "~5.2.0" 681 | 682 | strip-ansi@^6.0.1: 683 | version "6.0.1" 684 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 685 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 686 | dependencies: 687 | ansi-regex "^5.0.1" 688 | 689 | tar@^6.0.2, tar@^6.1.11, tar@^6.1.2: 690 | version "6.1.15" 691 | resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.15.tgz#c9738b0b98845a3b344d334b8fa3041aaba53a69" 692 | integrity sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A== 693 | dependencies: 694 | chownr "^2.0.0" 695 | fs-minipass "^2.0.0" 696 | minipass "^5.0.0" 697 | minizlib "^2.1.1" 698 | mkdirp "^1.0.3" 699 | yallist "^4.0.0" 700 | 701 | tr46@~0.0.3: 702 | version "0.0.3" 703 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" 704 | integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== 705 | 706 | unique-filename@^1.1.1: 707 | version "1.1.1" 708 | resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" 709 | integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== 710 | dependencies: 711 | unique-slug "^2.0.0" 712 | 713 | unique-slug@^2.0.0: 714 | version "2.0.2" 715 | resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" 716 | integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== 717 | dependencies: 718 | imurmurhash "^0.1.4" 719 | 720 | util-deprecate@^1.0.1: 721 | version "1.0.2" 722 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 723 | integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== 724 | 725 | webidl-conversions@^3.0.0: 726 | version "3.0.1" 727 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" 728 | integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== 729 | 730 | whatwg-url@^5.0.0: 731 | version "5.0.0" 732 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" 733 | integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== 734 | dependencies: 735 | tr46 "~0.0.3" 736 | webidl-conversions "^3.0.0" 737 | 738 | which@^2.0.2: 739 | version "2.0.2" 740 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 741 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 742 | dependencies: 743 | isexe "^2.0.0" 744 | 745 | wide-align@^1.1.2, wide-align@^1.1.5: 746 | version "1.1.5" 747 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" 748 | integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== 749 | dependencies: 750 | string-width "^1.0.2 || 2 || 3 || 4" 751 | 752 | wrappy@1: 753 | version "1.0.2" 754 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 755 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 756 | 757 | yallist@^4.0.0: 758 | version "4.0.0" 759 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" 760 | integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== 761 | --------------------------------------------------------------------------------