diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 0000000..9dbcc37 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,23 @@ +name: Publish + +on: + push: + branches: [master] + +jobs: + version: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: pnpm/action-setup@v2 + with: + version: 7.2.1 + - uses: actions/setup-node@v3 + with: + node-version: 18.x + cache: 'pnpm' + - run: pnpm install --frozen-lockfile + - run: | + echo "//registry.npmjs.org/:_authToken="${{secrets.NPM_TOKEN}}"" > ~/.npmrc + shell: sh + - run: pnpm -r --filter='./packages/*' publish --access public diff --git a/README.md b/README.md index 094bcb1..aa09a13 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # stenodb [![](https://img.shields.io/npm/v/stenodb)](https://www.npmjs.org/package/stenodb) -> ✍ Easy to use local JSON database. Ready to use with [LocalStorage](https://developer.mozilla.org/ru/docs/Web/API/Window/localStorage), [SessionStorage](https://developer.mozilla.org/ru/docs/Web/API/Window/sessionStorage) and Node.js. +> ✍ Easy to use local JSON database. Ready to use in browser (localStorage, sessionStorage) and Node.js. ## Install @@ -16,14 +16,20 @@ yarn add stenodb pnpm add stenodb ``` +| Package | Version | Platform | +| ------- | ------ | ----------- | +| [stenodb](./packages/stenodb) | [![](https://img.shields.io/npm/v/stenodb)](https://npm.im/stenodb) | Reexports packages | +| [@stenodb/node](./packages/node) | [![](https://img.shields.io/npm/v/@stenodb/node)](https://npm.im/@stenodb/node) | Node.js | +| [@stenodb/browser](./packages/browser) | [![](https://img.shields.io/npm/v/@stenodb/browser)](https://npm.im/@stenodb/browser) | Browser | + ## Usage > **Warning**\ > stenodb is a pure ESM package. If you're having trouble using it in your project, please [read this](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). - -### Entity +### Database entities ```typescript +// entities.ts import { Type } from 'class-transformer' export class Users { @@ -60,55 +66,48 @@ export class Post { } ``` -### Node.js +### `@stenodb/node` ```typescript import 'reflect-metadata' -import { join } from 'node:path' -import { NodeProvider } from 'stenodb/node' +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import { AsyncWriter, NodeDatabase } from '@stenodb/node' import { Users, User, Post } from './entities.js' const path = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'database') +const adapter = new AsyncWriter('users', Users) +const initialData = new Users(new User('John Doe')) +const database = new NodeDatabase(path) +const databaseUsers = database.create(adapter, initialData) -const databaseProvider = new NodeProvider({ - path, - logger: { enabled: true } -}) - -const databaseUsers = databaseProvider.createDatabase({ - name: 'users', - entity: Users, - initialData: new Users(new User('John Doe')) -}) - +await databaseUsers.read() databaseUsers.data?.users[0]?.addPost(new Post('Lorem ipsum')) -databaseUsers.write() +await databaseUsers.write() ``` -### Browser +### `@stenodb/browser` ```typescript import 'reflect-metadata' -import { BrowserProvider, LocalStorage } from 'stenodb/browser' +import { LocalStorage, BrowserDatabase } from '@stenodb/browser' import { Users, User, Post } from './entities.js' -const adapter = new LocalStorage('users') - -const databaseUsers = new BrowserProvider({ - adapter, - entity: Users, - initialData: new Users(new User('John Doe')) -}) +const adapter = new LocalStorage('users', Users) +const initialData = new Users(new User('John Doe')) +const databaseUsers = new BrowserDatabase(adapter, initialData) +databaseUsers.read() databaseUsers.data?.users[0]?.addPost(new Post('Lorem ipsum')) databaseUsers.write() ``` -## Related +## Credits - [steno](https://github.com/typicode/steno) - Specialized fast async file writer. - [class-transformer](https://github.com/typestack/class-transformer) - Decorator-based transformation, serialization, and deserialization between objects and classes. - [class-validator](https://github.com/typestack/class-validator) - Decorator-based property validation for classes. - [json-difference](https://github.com/lukascivil/json-difference) - A simple way to find the difference between two objects or json diff. +- [tslog](https://github.com/fullstack-build/tslog) - Universal Logger for TypeScript and JavaScript. ## License diff --git a/examples/with-lodash/index.html b/examples/with-browser-lodash/index.html similarity index 100% rename from examples/with-lodash/index.html rename to examples/with-browser-lodash/index.html diff --git a/examples/with-lodash/package.json b/examples/with-browser-lodash/package.json similarity index 79% rename from examples/with-lodash/package.json rename to examples/with-browser-lodash/package.json index 4da921e..9f7b2bb 100644 --- a/examples/with-lodash/package.json +++ b/examples/with-browser-lodash/package.json @@ -1,5 +1,5 @@ { - "name": "with-lodash", + "name": "with-browser-lodash", "private": true, "version": "0.0.0", "type": "module", @@ -14,10 +14,10 @@ "vite": "4.0.4" }, "dependencies": { + "@stenodb/browser": "workspace:*", "@zero-dependency/dom": "0.12.0", "class-transformer": "0.5.1", "lodash": "4.17.21", - "reflect-metadata": "0.1.13", - "stenodb": "workspace:*" + "reflect-metadata": "0.1.13" } } diff --git a/examples/with-lodash/src/entities.ts b/examples/with-browser-lodash/src/entities.ts similarity index 100% rename from examples/with-lodash/src/entities.ts rename to examples/with-browser-lodash/src/entities.ts diff --git a/examples/with-lodash/src/index.ts b/examples/with-browser-lodash/src/index.ts similarity index 86% rename from examples/with-lodash/src/index.ts rename to examples/with-browser-lodash/src/index.ts index 271ef01..afff6d5 100644 --- a/examples/with-lodash/src/index.ts +++ b/examples/with-browser-lodash/src/index.ts @@ -1,7 +1,7 @@ import 'reflect-metadata' import { el } from '@zero-dependency/dom' import { User } from './entities.js' -import { storage } from './storage.js' +import { addUser, getLastUserId, storage } from './storage.js' const app = document.querySelector('#app')! @@ -48,7 +48,7 @@ const form = el( return } - storage.addUser(new User(storage.getLastUserId() + 1, username)) + addUser(new User(getLastUserId() + 1, username)) render() } }, @@ -63,7 +63,7 @@ const storagePreview = el('pre') function render() { form.reset() usernameInput.focus() - userIdInput.value = storage.getLastUserId().toString() + userIdInput.value = getLastUserId().toString() storagePreview.textContent = JSON.stringify(storage.data, null, 2) } diff --git a/examples/with-browser-lodash/src/storage.ts b/examples/with-browser-lodash/src/storage.ts new file mode 100644 index 0000000..2cf0f21 --- /dev/null +++ b/examples/with-browser-lodash/src/storage.ts @@ -0,0 +1,27 @@ +import { BrowserDatabase, LocalStorage } from '@stenodb/browser' +import lodash from 'lodash' +import { User, Users } from './entities.js' +import type { BrowserAdapter } from '@stenodb/browser/types' + +class StorageWithLodash extends BrowserDatabase { + chain: lodash.ExpChain = lodash.chain(this).get('data') + + constructor(adapter: BrowserAdapter, initialData: T) { + super(adapter, initialData) + } +} + +const adapter = new LocalStorage('users', Users) +const initialData = new Users(new User(1, 'John')) + +export const storage = new StorageWithLodash(adapter, initialData) +storage.read() + +export function addUser(user: User): void { + storage.chain.get('users').push(user).value() + storage.write() +} + +export function getLastUserId(): number { + return storage.chain.get('users').last().get('id').value() +} diff --git a/examples/with-lodash/src/vite-env.d.ts b/examples/with-browser-lodash/src/vite-env.d.ts similarity index 100% rename from examples/with-lodash/src/vite-env.d.ts rename to examples/with-browser-lodash/src/vite-env.d.ts diff --git a/examples/with-lodash/tsconfig.json b/examples/with-browser-lodash/tsconfig.json similarity index 100% rename from examples/with-lodash/tsconfig.json rename to examples/with-browser-lodash/tsconfig.json diff --git a/examples/with-browser/package.json b/examples/with-browser/package.json index 0f75071..19d8a33 100644 --- a/examples/with-browser/package.json +++ b/examples/with-browser/package.json @@ -9,13 +9,13 @@ "preview": "vite preview" }, "devDependencies": { - "typescript": "4.9.4", - "vite": "4.0.4" + "typescript": "4.9.5", + "vite": "4.1.1" }, "dependencies": { + "@stenodb/browser": "workspace:*", "@zero-dependency/dom": "0.12.0", "class-transformer": "0.5.1", - "reflect-metadata": "0.1.13", - "stenodb": "workspace:*" + "reflect-metadata": "0.1.13" } } diff --git a/examples/with-browser/src/index.ts b/examples/with-browser/src/index.ts index 8a235c4..10c5681 100644 --- a/examples/with-browser/src/index.ts +++ b/examples/with-browser/src/index.ts @@ -47,9 +47,8 @@ const form = el( usernameInput.focus() return } - storage.data!.addUser( - new User(storage.data!.getLastUserId() + 1, username) - ) + const user = new User(storage.data!.getLastUserId() + 1, username) + storage.data!.addUser(user) storage.write() render() } diff --git a/examples/with-browser/src/storage.ts b/examples/with-browser/src/storage.ts index 1b038a2..03c593c 100644 --- a/examples/with-browser/src/storage.ts +++ b/examples/with-browser/src/storage.ts @@ -1,10 +1,7 @@ -import { BrowserProvider, LocalStorage } from 'stenodb/browser' +import { BrowserDatabase, LocalStorage } from '@stenodb/browser' import { User, Users } from './entities.js' -const adapter = new LocalStorage('users') - -export const storage = new BrowserProvider({ - adapter, - entity: Users, - initialData: new Users(new User(1, 'John')) -}) +const adapter = new LocalStorage('users', Users) +const initialData = new Users(new User(1, 'John')) +export const storage = new BrowserDatabase(adapter, initialData) +storage.read() diff --git a/examples/with-lodash/src/storage.ts b/examples/with-lodash/src/storage.ts deleted file mode 100644 index 630ca8b..0000000 --- a/examples/with-lodash/src/storage.ts +++ /dev/null @@ -1,26 +0,0 @@ -import lodash from 'lodash' -import { BrowserProvider, LocalStorage } from 'stenodb/browser' -import { User, Users } from './entities.js' - -class StorageWithLodash extends BrowserProvider { - chain: lodash.ExpChain = lodash.chain(this).get('data') - - constructor() { - super({ - entity: Users, - adapter: new LocalStorage('users'), - initialData: new Users(new User(1, 'John')) - }) - } - - addUser(user: User): void { - this.chain.get('users').push(user).value() - this.write() - } - - getLastUserId(): number { - return this.chain.get('users').last().get('id').value() - } -} - -export const storage = new StorageWithLodash() diff --git a/examples/with-node-lodash/nodemon.json b/examples/with-node-lodash/nodemon.json new file mode 100644 index 0000000..6028c9c --- /dev/null +++ b/examples/with-node-lodash/nodemon.json @@ -0,0 +1,8 @@ +{ + "watch": [ + "src" + ], + "ignore": ["database", "dist"], + "exec": "cross-env TS_NODE_TRANSPILE_ONLY=true NODE_ENV=development node --no-warnings --loader ts-node/esm --enable-source-maps --trace-warnings --inspect=0.0.0.0:9234 --nolazy src/index.ts", + "ext": "ts" +} diff --git a/examples/with-node-lodash/package.json b/examples/with-node-lodash/package.json new file mode 100644 index 0000000..9bfd17a --- /dev/null +++ b/examples/with-node-lodash/package.json @@ -0,0 +1,20 @@ +{ + "name": "with-node-lodash", + "type": "module", + "private": true, + "scripts": { + "start": "pnpm build && node dist/index.js", + "dev": "nodemon", + "build": "del-cli dist && tsc" + }, + "dependencies": { + "@stenodb/node": "workspace:*", + "class-transformer": "0.5.1", + "lodash": "4.17.21", + "reflect-metadata": "0.1.13" + }, + "devDependencies": { + "@types/node": "18.11.19", + "@types/lodash": "4.14.191" + } +} diff --git a/examples/with-node-lodash/src/entities.ts b/examples/with-node-lodash/src/entities.ts new file mode 100644 index 0000000..56c0422 --- /dev/null +++ b/examples/with-node-lodash/src/entities.ts @@ -0,0 +1,20 @@ +import { Type } from 'class-transformer' + +export class Users { + @Type(() => User) + users: User[] + + constructor(...users: User[]) { + this.users = users + } +} + +export class User { + id: number + username: string + + constructor(id: number, username: string) { + this.id = id + this.username = username + } +} diff --git a/examples/with-node-lodash/src/index.ts b/examples/with-node-lodash/src/index.ts new file mode 100644 index 0000000..4fc551c --- /dev/null +++ b/examples/with-node-lodash/src/index.ts @@ -0,0 +1,41 @@ +import 'reflect-metadata' +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import { AsyncWriter, NodeDatabase } from '@stenodb/node' +import lodash from 'lodash' +import { User, Users } from './entities.js' +import type { NodeProvider } from '@stenodb/node/types' + +export class NodeWithLodash { + chain: lodash.ExpChain + + constructor(private readonly provider: NodeProvider) { + this.chain = lodash.chain(provider).get('data') + } + + get data(): T | null { + return this.provider.data + } + + async read(): Promise { + await this.provider.read() + } + + async write(): Promise { + await this.provider.write() + } +} + +const path = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'database') +const adapter = new AsyncWriter('users', Users) +const initialData = new Users(new User(1, 'John Doe')) +const database = new NodeDatabase(path) + +const usersDatabase = new NodeWithLodash(database.create(adapter, initialData)) +await usersDatabase.read() + +function findUserById(id: number) { + return usersDatabase.chain.get('users').find({ id }).value() +} + +console.log(findUserById(1)) diff --git a/examples/with-node-lodash/tsconfig.json b/examples/with-node-lodash/tsconfig.json new file mode 100644 index 0000000..8e23fbf --- /dev/null +++ b/examples/with-node-lodash/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "@crashmax/tsconfig", + "compilerOptions": { + "moduleResolution": "NodeNext", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/examples/with-node/package.json b/examples/with-node/package.json index fd5205b..58c87d4 100644 --- a/examples/with-node/package.json +++ b/examples/with-node/package.json @@ -8,8 +8,11 @@ "build": "del-cli dist && tsc" }, "dependencies": { + "@stenodb/node": "workspace:*", "class-transformer": "0.5.1", - "reflect-metadata": "0.1.13", - "stenodb": "workspace:*" + "reflect-metadata": "0.1.13" + }, + "devDependencies": { + "@types/node": "18.11.19" } } diff --git a/examples/with-node/src/entities.ts b/examples/with-node/src/entities.ts index 9911608..e066554 100644 --- a/examples/with-node/src/entities.ts +++ b/examples/with-node/src/entities.ts @@ -3,6 +3,10 @@ import { Type } from 'class-transformer' export class Users { @Type(() => User) users: User[] + + constructor(...users: User[]) { + this.users = users + } } export class User { diff --git a/examples/with-node/src/index.ts b/examples/with-node/src/index.ts index 49592b7..7848883 100644 --- a/examples/with-node/src/index.ts +++ b/examples/with-node/src/index.ts @@ -1,23 +1,19 @@ import 'reflect-metadata' import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' -import { NodeProvider } from 'stenodb/node' +import { AsyncWriter, NodeDatabase } from '@stenodb/node' import { Post, User, Users } from './entities.js' const path = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'database') +const adapter = new AsyncWriter('users', Users) +const initialData = new Users(new User('John Doe')) +const database = new NodeDatabase(path) -const databaseProvider = new NodeProvider({ - path, - logger: { enabled: true } -}) +const usersDatabase = database.create(adapter, initialData) +await usersDatabase.read() -const databaseUsers = databaseProvider.createDatabase({ - name: 'users', - entity: Users, - initialData: { - users: [new User('John Doe')] - } -}) +const post = new Post('Hello world') +usersDatabase.data?.users[0]?.addPost(post) +await usersDatabase.write() -databaseUsers.data?.users[0]?.addPost(new Post('Lorem ipsum')) -databaseUsers.write() +console.log(usersDatabase.data) diff --git a/examples/with-node/tsconfig.json b/examples/with-node/tsconfig.json index e4cddaf..8e23fbf 100644 --- a/examples/with-node/tsconfig.json +++ b/examples/with-node/tsconfig.json @@ -2,9 +2,6 @@ "extends": "@crashmax/tsconfig", "compilerOptions": { "moduleResolution": "NodeNext", - "strictNullChecks": true, - "noPropertyAccessFromIndexSignature": false, - "noImplicitOverride": false, "experimentalDecorators": true, "emitDecoratorMetadata": true, "outDir": "dist" diff --git a/package.json b/package.json index 7a37cc3..52da741 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "@stenodb/workspace", - "version": "0.0.0", + "version": "2.0.0", + "type": "module", "private": true, "workspaces": [ "examples/*", @@ -11,22 +12,21 @@ "dev:examples": "turbo run dev --filter=./examples/*", "build": "turbo run build --filter=./packages/*", "build:examples": "turbo run build --filter=./examples/*", - "format": "prettier --write --ignore-unknown **", - "prepare": "pnpm build" + "format": "prettier --write --ignore-unknown **" }, "devDependencies": { "@crashmax/prettier-config": "2.2.1", "@crashmax/tsconfig": "1.0.2", - "@types/node": "18.11.18", "cross-env": "7.0.3", "del-cli": "5.0.0", "nodemon": "2.0.20", "ts-node": "10.9.1", "tsx": "3.12.2", - "turbo": "^1.7.0", - "typescript": "4.9.4" + "turbo": "1.7.2", + "typescript": "4.9.5" }, "engines": { - "node": ">=16" - } + "node": ">=14.16" + }, + "packageManager": "pnpm@7.10.0" } diff --git a/packages/browser/README.md b/packages/browser/README.md new file mode 100644 index 0000000..ed58a2a --- /dev/null +++ b/packages/browser/README.md @@ -0,0 +1,87 @@ +# @stenodb/browser [![](https://img.shields.io/npm/v/@stenodb/browser)](https://www.npmjs.org/package/@stenodb/browser) + +> ✍ Easy to use local JSON database for [LocalStorage](https://developer.mozilla.org/ru/docs/Web/API/Window/localStorage) and [SessionStorage](https://developer.mozilla.org/ru/docs/Web/API/Window/sessionStorage). + +## Install + +```sh +npm install @stenodb/browser +``` + +```sh +yarn add @stenodb/browser +``` + +```sh +pnpm add @stenodb/browser +``` + +## Usage + +> **Warning**\ +> stenodb is a pure ESM package. If you're having trouble using it in your project, please [read this](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). + +```typescript +// entities.ts +import { Type } from 'class-transformer' + +export class Users { + @Type(() => User) + users: User[] + + constructor(...users: User[]) { + this.users = users + } +} + +export class User { + username: string + + @Type(() => Post) + posts: Post[] + + constructor(username: string, ...posts: Post[]) { + this.username = username + this.posts = posts + } + + addPost(post: Post) { + this.posts.push(post) + } +} + +export class Post { + title: string + + constructor(text: string) { + this.title = title + } +} +``` + +```typescript +// index.ts +import 'reflect-metadata' +import { LocalStorage, BrowserDatabase } from '@stenodb/browser' +import { Users, User, Post } from './entities.js' + +const adapter = new LocalStorage('users', Users) +const initialData = new Users(new User('John Doe')) +const databaseUsers = new BrowserDatabase(adapter, initialData) + +databaseUsers.read() +databaseUsers.data?.users[0]?.addPost(new Post('Lorem ipsum')) +databaseUsers.write() +``` + +## Credits + +- [steno](https://github.com/typicode/steno) - Specialized fast async file writer. +- [class-transformer](https://github.com/typestack/class-transformer) - Decorator-based transformation, serialization, and deserialization between objects and classes. +- [class-validator](https://github.com/typestack/class-validator) - Decorator-based property validation for classes. +- [json-difference](https://github.com/lukascivil/json-difference) - A simple way to find the difference between two objects or json diff. +- [tslog](https://github.com/fullstack-build/tslog) - Universal Logger for TypeScript and JavaScript. + +## License + +MIT - [crashmax](https://github.com/crashmax-dev) diff --git a/packages/browser/package.json b/packages/browser/package.json new file mode 100644 index 0000000..7f055d3 --- /dev/null +++ b/packages/browser/package.json @@ -0,0 +1,61 @@ +{ + "name": "@stenodb/browser", + "description": "✍ Easy to use local JSON database", + "version": "2.0.0", + "type": "module", + "files": [ + "dist" + ], + "types": "dist", + "typesVersions": { + "*": { + "types": [ + "./dist/types.d.ts" + ] + } + }, + "exports": { + ".": "./dist/index.js", + "./types": "./dist/types.js" + }, + "author": { + "name": "Vitalij Ryndin", + "email": "sys@crashmax.ru", + "url": "https://crashmax.ru" + }, + "license": "MIT", + "homepage": "https://github.com/crashmax-dev/stenodb/packages/browser#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/crashmax-dev/stenodb.git" + }, + "bugs": { + "url": "https://github.com/crashmax-dev/stenodb/issues" + }, + "keywords": [ + "db", + "database", + "browser", + "local", + "localStorage", + "sessionStorage", + "class-transformer", + "JSON", + "ESM" + ], + "scripts": { + "dev": "tsc --watch", + "build": "del-cli dist && tsc", + "prepublishOnly": "pnpm build" + }, + "dependencies": { + "@stenodb/utils": "workspace:2.0.0", + "class-transformer": "0.5.1" + }, + "peerDependencies": { + "class-transformer": ">=0.5.0" + }, + "engines": { + "node": ">=14.16" + } +} diff --git a/packages/browser/src/BrowserDatabase.ts b/packages/browser/src/BrowserDatabase.ts new file mode 100644 index 0000000..0c46bfd --- /dev/null +++ b/packages/browser/src/BrowserDatabase.ts @@ -0,0 +1,9 @@ +import { BrowserProvider } from './BrowserProvider.js' +import type { BrowserAdapter } from './types.js' + +export class BrowserDatabase extends BrowserProvider { + constructor(adapter: BrowserAdapter, initialData?: T) { + super(adapter) + this.initialData = initialData + } +} diff --git a/packages/browser/src/BrowserProvider.ts b/packages/browser/src/BrowserProvider.ts new file mode 100644 index 0000000..e78ab62 --- /dev/null +++ b/packages/browser/src/BrowserProvider.ts @@ -0,0 +1,55 @@ +import { plainToClass } from 'class-transformer' +import type { BrowserAdapter } from './types.js' + +export class BrowserProvider { + #adapter: BrowserAdapter + #data: T | null = null + #initialData: T | null = null + + constructor(adapter: BrowserAdapter) { + this.#adapter = adapter + } + + get data(): T | null { + return this.#data + } + + set data(data: T | null) { + this.#data = data + } + + get initialData(): T | null { + return this.#initialData + } + + set initialData(data: T | undefined | null) { + if (!data) return + this.#initialData = data + } + + read(): T | null { + this.#data = this.#adapter.read() + + if (!this.#data) { + this.reset() + } else { + this.#data = plainToClass(this.#adapter.entity, this.#data) + } + + return this.#data + } + + write(): void { + this.#adapter.write(this.#data) + } + + reset(): void { + if (!this.#initialData) return + this.#data = plainToClass(this.#adapter.entity, this.#initialData) + this.#adapter.write(this.#data) + } + + exists(): boolean { + return this.#adapter.exists() + } +} diff --git a/packages/browser/src/adapter/LocalStorage.ts b/packages/browser/src/adapter/LocalStorage.ts new file mode 100644 index 0000000..868e63c --- /dev/null +++ b/packages/browser/src/adapter/LocalStorage.ts @@ -0,0 +1,8 @@ +import { BrowserStorage } from './WebStorage.js' +import type { Entity } from '../types.js' + +export class LocalStorage extends BrowserStorage { + constructor(name: string, entity: Entity) { + super(name, localStorage, entity) + } +} diff --git a/packages/browser/src/adapter/SessionStorage.ts b/packages/browser/src/adapter/SessionStorage.ts new file mode 100644 index 0000000..e3c102f --- /dev/null +++ b/packages/browser/src/adapter/SessionStorage.ts @@ -0,0 +1,8 @@ +import { BrowserStorage } from './WebStorage.js' +import type { Entity } from '../types.js' + +export class SessionStorage extends BrowserStorage { + constructor(name: string, entity: Entity) { + super(name, sessionStorage, entity) + } +} diff --git a/packages/browser/src/adapter/WebStorage.ts b/packages/browser/src/adapter/WebStorage.ts new file mode 100644 index 0000000..1be65ca --- /dev/null +++ b/packages/browser/src/adapter/WebStorage.ts @@ -0,0 +1,37 @@ +import { parseData } from '@stenodb/utils' +import type { Entity } from '../types.js' + +interface SyncAdapter { + read(): T | null + write(data: T | null): void + exists(): boolean +} + +export class BrowserStorage implements SyncAdapter { + #name: string + #storage: Storage + #entity: Entity + + constructor(name: string, storage: Storage, entity: Entity) { + this.#name = name + this.#storage = storage + this.#entity = entity + } + + get entity(): Entity { + return this.#entity + } + + read(): T | null { + const data = this.#storage.getItem(this.#name) + return data ? parseData(data).toJSON() : null + } + + write(data: T | null): void { + this.#storage.setItem(this.#name, parseData(data).toString()) + } + + exists(): boolean { + return this.read() !== null + } +} diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts new file mode 100644 index 0000000..c4a0554 --- /dev/null +++ b/packages/browser/src/index.ts @@ -0,0 +1,3 @@ +export * from './adapter/LocalStorage.js' +export * from './adapter/SessionStorage.js' +export * from './BrowserDatabase.js' diff --git a/packages/browser/src/types.ts b/packages/browser/src/types.ts new file mode 100644 index 0000000..a670d4c --- /dev/null +++ b/packages/browser/src/types.ts @@ -0,0 +1,6 @@ +import type { LocalStorage } from './adapter/LocalStorage.js' +import type { SessionStorage } from './adapter/SessionStorage.js' +import type { ClassConstructor } from 'class-transformer' + +export type Entity = ClassConstructor +export type BrowserAdapter = LocalStorage | SessionStorage diff --git a/packages/browser/tsconfig.json b/packages/browser/tsconfig.json new file mode 100644 index 0000000..43493c0 --- /dev/null +++ b/packages/browser/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@crashmax/tsconfig", + "compilerOptions": { + "moduleResolution": "NodeNext", + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/packages/node/README.md b/packages/node/README.md new file mode 100644 index 0000000..617190b --- /dev/null +++ b/packages/node/README.md @@ -0,0 +1,91 @@ +# @stenodb/node [![](https://img.shields.io/npm/v/@stenodb/node)](https://www.npmjs.org/package/@stenodb/node) + +> ✍ Easy to use local JSON database. + +## Install + +```sh +npm install @stenodb/node +``` + +```sh +yarn add @stenodb/node +``` + +```sh +pnpm add @stenodb/node +``` + +## Usage + +> **Warning**\ +> stenodb is a pure ESM package. If you're having trouble using it in your project, please [read this](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). + +```typescript +// entities.ts +import { Type } from 'class-transformer' + +export class Users { + @Type(() => User) + users: User[] + + constructor(...users: User[]) { + this.users = users + } +} + +export class User { + username: string + + @Type(() => Post) + posts: Post[] + + constructor(username: string, ...posts: Post[]) { + this.username = username + this.posts = posts + } + + addPost(post: Post) { + this.posts.push(post) + } +} + +export class Post { + title: string + + constructor(text: string) { + this.title = title + } +} +``` + +```typescript +// index.ts +import 'reflect-metadata' +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import { AsyncWriter, NodeDatabase } from '@stenodb/node' +import { Users, User, Post } from './entities.js' + +const path = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'database') +const adapter = new AsyncWriter('users', Users) +const initialData = new Users(new User('John Doe')) +const database = new NodeDatabase(path) +const databaseUsers = database.create(adapter, initialData) + +await databaseUsers.read() +databaseUsers.data?.users[0]?.addPost(new Post('Lorem ipsum')) +await databaseUsers.write() +``` + +## Credits + +- [steno](https://github.com/typicode/steno) - Specialized fast async file writer. +- [class-transformer](https://github.com/typestack/class-transformer) - Decorator-based transformation, serialization, and deserialization between objects and classes. +- [class-validator](https://github.com/typestack/class-validator) - Decorator-based property validation for classes. +- [json-difference](https://github.com/lukascivil/json-difference) - A simple way to find the difference between two objects or json diff. +- [tslog](https://github.com/fullstack-build/tslog) - Universal Logger for TypeScript and JavaScript. + +## License + +MIT - [crashmax](https://github.com/crashmax-dev) diff --git a/packages/node/package.json b/packages/node/package.json new file mode 100644 index 0000000..0f540cf --- /dev/null +++ b/packages/node/package.json @@ -0,0 +1,62 @@ +{ + "name": "@stenodb/node", + "description": "✍ Easy to use local JSON database", + "version": "2.0.0", + "type": "module", + "files": [ + "dist" + ], + "types": "dist", + "typesVersions": { + "*": { + "types": [ + "./dist/types.d.ts" + ] + } + }, + "exports": { + ".": "./dist/index.js", + "./types": "./dist/types.js" + }, + "author": { + "name": "Vitalij Ryndin", + "email": "sys@crashmax.ru", + "url": "https://crashmax.ru" + }, + "license": "MIT", + "homepage": "https://github.com/crashmax-dev/stenodb/packages/node#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/crashmax-dev/stenodb.git" + }, + "bugs": { + "url": "https://github.com/crashmax-dev/stenodb/issues" + }, + "keywords": [ + "db", + "database", + "local", + "class-transformer", + "JSON", + "ESM" + ], + "scripts": { + "dev": "tsc --watch", + "build": "del-cli dist && tsc", + "prepublishOnly": "pnpm build" + }, + "dependencies": { + "@stenodb/utils": "workspace:2.0.0", + "class-transformer": "0.5.1", + "steno": "3.0.0" + }, + "devDependencies": { + "@types/node": "18.11.19" + }, + "peerDependencies": { + "class-transformer": ">=0.5.0" + }, + "engines": { + "node": ">=14.16" + } +} diff --git a/packages/node/src/DirectoryProvider.ts b/packages/node/src/DirectoryProvider.ts new file mode 100644 index 0000000..08e05f3 --- /dev/null +++ b/packages/node/src/DirectoryProvider.ts @@ -0,0 +1,57 @@ +import { lstatSync, mkdir, readFile, rmSync } from 'node:fs' +import { join } from 'node:path' +import { parseData } from '@stenodb/utils' +import { Writer } from 'steno' + +export class DirectoryProvider { + databasePath: string + temporaryPath: string + + constructor(path: string) { + // if (!lstatSync(path).isDirectory()) { + // throw new Error('Path must be a directory') + // } + + this.databasePath = path + this.temporaryPath = join(this.databasePath, 'temp') + this.createDatabaseDir() + } + + private createDatabaseDir(): void { + mkdir(this.temporaryPath, { recursive: true }, (err) => { + if (err) throw err + }) + } + + removeFile(path: string, size = 0): void { + readFile(path, (err, buffer) => { + if (err) return + + if (size > 0 || buffer.byteLength === size) { + rmSync(path) + } + }) + } + + databaseFilePath(filename: string): string { + return join(this.databasePath, `${filename}.json`) + } + + temporaryFilePath(filename: string): string { + return join(this.temporaryPath, `${filename}-${Date.now()}.json`) + } + + createTemporaryFile(filename: string, data: T | null) { + if (!data) return + + const file = this.temporaryFilePath(filename) + const writer = new Writer(file) + const parsedData = + typeof data === 'string' ? data : parseData(data).toString() + + return { + write: () => writer.write(parsedData), + writeAsync: async () => await writer.write(parsedData) + } + } +} diff --git a/packages/node/src/NodeDatabase.ts b/packages/node/src/NodeDatabase.ts new file mode 100644 index 0000000..bd7b90c --- /dev/null +++ b/packages/node/src/NodeDatabase.ts @@ -0,0 +1,30 @@ +import { AsyncWriter } from './adapter/AsyncWriter.js' +import { SyncWriter } from './adapter/SyncWriter.js' +import { DirectoryProvider } from './DirectoryProvider.js' +import { AsyncProvider } from './provider/AsyncProvider.js' +import { SyncProvider } from './provider/SyncProvider.js' +import type { NodeAdapter, NodeProvider } from './types.js' + +export class NodeDatabase { + #directory: DirectoryProvider + + constructor(path: string) { + this.#directory = new DirectoryProvider(path) + } + + create(adapter: SyncWriter, initialData?: T): SyncProvider + create(adapter: AsyncWriter, initialData?: T): AsyncProvider + create(adapter: NodeAdapter, initialData?: T): NodeProvider { + adapter.setDirectory(this.#directory) + + if (adapter instanceof SyncWriter) { + return new SyncProvider(adapter, initialData) + } + + if (adapter instanceof AsyncWriter) { + return new AsyncProvider(adapter, initialData) + } + + throw new Error('Invalid adapter') + } +} diff --git a/packages/node/src/adapter/AsyncWriter.ts b/packages/node/src/adapter/AsyncWriter.ts new file mode 100644 index 0000000..807c007 --- /dev/null +++ b/packages/node/src/adapter/AsyncWriter.ts @@ -0,0 +1,52 @@ +import { readFile } from 'node:fs/promises' +import { parseData } from '@stenodb/utils' +import { BaseWriter } from './BaseWriter.js' +import type { Entity } from '../types.js' + +interface AsyncAdapter { + read(): Promise + write(data: T | null): Promise + reset(initialData: T): Promise + exists(): Promise +} + +export class AsyncWriter extends BaseWriter implements AsyncAdapter { + constructor(name: string, entity: Entity) { + super(name, entity) + } + + async read(): Promise { + try { + const data = await readFile(this.file, 'utf-8') + return parseData(data).toJSON() + } catch (err) { + if ((err as NodeJS.ErrnoException).code === 'ENOENT') { + return null + } + + throw err + } + } + + async write(data: T | null): Promise { + await this.writer.write(parseData(data).toString()) + } + + async reset(initialData: T): Promise { + try { + const data = await this.read() + await this.directory.createTemporaryFile(this.name, data)?.writeAsync() + await this.write(initialData) + } catch (err) { + if ((err as NodeJS.ErrnoException).code === 'ENOENT') { + this.write(initialData) + } + + throw err + } + } + + async exists(): Promise { + return (await this.read()) !== null + } +} diff --git a/packages/node/src/adapter/BaseWriter.ts b/packages/node/src/adapter/BaseWriter.ts new file mode 100644 index 0000000..baa8f1b --- /dev/null +++ b/packages/node/src/adapter/BaseWriter.ts @@ -0,0 +1,23 @@ +import { Writer } from 'steno' +import type { DirectoryProvider } from '../DirectoryProvider.js' +import type { Entity } from '../types.js' + +export class BaseWriter { + name: string + entity: Entity + + file: string + directory: DirectoryProvider + writer: Writer + + constructor(name: string, entity: Entity) { + this.name = name + this.entity = entity + } + + setDirectory(directory: DirectoryProvider): void { + this.directory = directory + this.file = this.directory.databaseFilePath(this.name) + this.writer = new Writer(this.file) + } +} diff --git a/packages/node/src/adapter/SyncWriter.ts b/packages/node/src/adapter/SyncWriter.ts new file mode 100644 index 0000000..d5121ea --- /dev/null +++ b/packages/node/src/adapter/SyncWriter.ts @@ -0,0 +1,48 @@ +import { readFileSync } from 'node:fs' +import { parseData } from '@stenodb/utils' +import { BaseWriter } from './BaseWriter.js' +import type { Entity } from '../types.js' + +interface SyncAdapter { + read(): T | null + write(data: T | null): void + reset(initialData: T): void + exists(): boolean +} + +export class SyncWriter extends BaseWriter implements SyncAdapter { + constructor(name: string, entity: Entity) { + super(name, entity) + } + + read(): T | null { + try { + const data = readFileSync(this.file, 'utf-8') + return parseData(data).toJSON() + } catch (err) { + if ((err as NodeJS.ErrnoException).code === 'ENOENT') { + return null + } + + throw err + } + } + + write(data: T | null): void { + this.writer.write(parseData(data).toString()) + } + + reset(initialData: T): void { + try { + const data = this.read() + this.directory.createTemporaryFile(this.name, data)?.write() + this.write(initialData) + } catch (err) { + throw err + } + } + + exists(): boolean { + return this.read() !== null + } +} diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts new file mode 100644 index 0000000..7183f32 --- /dev/null +++ b/packages/node/src/index.ts @@ -0,0 +1,3 @@ +export * from './adapter/AsyncWriter.js' +export * from './adapter/SyncWriter.js' +export * from './NodeDatabase.js' diff --git a/packages/node/src/provider/AsyncProvider.ts b/packages/node/src/provider/AsyncProvider.ts new file mode 100644 index 0000000..2758010 --- /dev/null +++ b/packages/node/src/provider/AsyncProvider.ts @@ -0,0 +1,39 @@ +import { plainToClass } from 'class-transformer' +import { AsyncWriter } from '../index.js' +import { BaseProvider } from './BaseProvider.js' + +export class AsyncProvider extends BaseProvider { + #adapter: AsyncWriter + + constructor(adapter: AsyncWriter, initialData?: T) { + super() + this.#adapter = adapter + this.initialData = initialData + } + + async read(): Promise { + this.data = await this.#adapter.read() + + if (!this.data) { + await this.reset() + } else { + this.data = plainToClass(this.#adapter.entity, this.data) + } + + return this.data + } + + async write(): Promise { + await this.#adapter.write(this.data) + } + + async reset(): Promise { + if (!this.initialData) return + this.data = plainToClass(this.#adapter.entity, this.initialData) + await this.#adapter.reset(this.data) + } + + async exists(): Promise { + return await this.#adapter.exists() + } +} diff --git a/packages/node/src/provider/BaseProvider.ts b/packages/node/src/provider/BaseProvider.ts new file mode 100644 index 0000000..d0ea3bf --- /dev/null +++ b/packages/node/src/provider/BaseProvider.ts @@ -0,0 +1,21 @@ +export class BaseProvider { + #data: T | null = null + #initialData: T | null = null + + get data(): T | null { + return this.#data + } + + set data(data: T | null) { + this.#data = data + } + + get initialData(): T | null { + return this.#initialData + } + + set initialData(data: T | undefined | null) { + if (!data) return + this.#initialData = data + } +} diff --git a/packages/node/src/provider/SyncProvider.ts b/packages/node/src/provider/SyncProvider.ts new file mode 100644 index 0000000..d841ece --- /dev/null +++ b/packages/node/src/provider/SyncProvider.ts @@ -0,0 +1,40 @@ +import { plainToClass } from 'class-transformer' +import { SyncWriter } from '../index.js' +import { BaseProvider } from './BaseProvider.js' + +export class SyncProvider extends BaseProvider { + #adapter: SyncWriter + + constructor(adapter: SyncWriter, initialData?: T) { + super() + + this.#adapter = adapter + this.initialData = initialData + } + + read(): T | null { + this.data = this.#adapter.read() + + if (!this.data) { + this.reset() + } else { + this.data = plainToClass(this.#adapter.entity, this.data) + } + + return this.data + } + + write(): void { + this.#adapter.write(this.data) + } + + reset(): void { + if (!this.initialData) return + this.data = plainToClass(this.#adapter.entity, this.initialData) + this.#adapter.reset(this.data) + } + + exists(): boolean { + return this.#adapter.exists() + } +} diff --git a/packages/node/src/types.ts b/packages/node/src/types.ts new file mode 100644 index 0000000..35fc652 --- /dev/null +++ b/packages/node/src/types.ts @@ -0,0 +1,9 @@ +import type { AsyncWriter } from './adapter/AsyncWriter.js' +import type { SyncWriter } from './adapter/SyncWriter.js' +import type { AsyncProvider } from './provider/AsyncProvider.js' +import type { SyncProvider } from './provider/SyncProvider.js' +import type { ClassConstructor } from 'class-transformer' + +export type Entity = ClassConstructor +export type NodeAdapter = AsyncWriter | SyncWriter +export type NodeProvider = AsyncProvider | SyncProvider diff --git a/packages/node/tsconfig.json b/packages/node/tsconfig.json new file mode 100644 index 0000000..43493c0 --- /dev/null +++ b/packages/node/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@crashmax/tsconfig", + "compilerOptions": { + "moduleResolution": "NodeNext", + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/packages/stenodb/README.md b/packages/stenodb/README.md index 1ff4289..aa09a13 100644 --- a/packages/stenodb/README.md +++ b/packages/stenodb/README.md @@ -1 +1,114 @@ -[README.md](../../README.md) +# stenodb [![](https://img.shields.io/npm/v/stenodb)](https://www.npmjs.org/package/stenodb) + +> ✍ Easy to use local JSON database. Ready to use in browser (localStorage, sessionStorage) and Node.js. + +## Install + +```sh +npm install stenodb +``` + +```sh +yarn add stenodb +``` + +```sh +pnpm add stenodb +``` + +| Package | Version | Platform | +| ------- | ------ | ----------- | +| [stenodb](./packages/stenodb) | [![](https://img.shields.io/npm/v/stenodb)](https://npm.im/stenodb) | Reexports packages | +| [@stenodb/node](./packages/node) | [![](https://img.shields.io/npm/v/@stenodb/node)](https://npm.im/@stenodb/node) | Node.js | +| [@stenodb/browser](./packages/browser) | [![](https://img.shields.io/npm/v/@stenodb/browser)](https://npm.im/@stenodb/browser) | Browser | + +## Usage + +> **Warning**\ +> stenodb is a pure ESM package. If you're having trouble using it in your project, please [read this](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). + +### Database entities +```typescript +// entities.ts +import { Type } from 'class-transformer' + +export class Users { + @Type(() => User) + users: User[] + + constructor(...users: User[]) { + this.users = users + } +} + +export class User { + username: string + + @Type(() => Post) + posts: Post[] + + constructor(username: string, ...posts: Post[]) { + this.username = username + this.posts = posts + } + + addPost(post: Post) { + this.posts.push(post) + } +} + +export class Post { + title: string + + constructor(text: string) { + this.title = title + } +} +``` + +### `@stenodb/node` + +```typescript +import 'reflect-metadata' +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import { AsyncWriter, NodeDatabase } from '@stenodb/node' +import { Users, User, Post } from './entities.js' + +const path = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'database') +const adapter = new AsyncWriter('users', Users) +const initialData = new Users(new User('John Doe')) +const database = new NodeDatabase(path) +const databaseUsers = database.create(adapter, initialData) + +await databaseUsers.read() +databaseUsers.data?.users[0]?.addPost(new Post('Lorem ipsum')) +await databaseUsers.write() +``` + +### `@stenodb/browser` +```typescript +import 'reflect-metadata' +import { LocalStorage, BrowserDatabase } from '@stenodb/browser' +import { Users, User, Post } from './entities.js' + +const adapter = new LocalStorage('users', Users) +const initialData = new Users(new User('John Doe')) +const databaseUsers = new BrowserDatabase(adapter, initialData) + +databaseUsers.read() +databaseUsers.data?.users[0]?.addPost(new Post('Lorem ipsum')) +databaseUsers.write() +``` + +## Credits + +- [steno](https://github.com/typicode/steno) - Specialized fast async file writer. +- [class-transformer](https://github.com/typestack/class-transformer) - Decorator-based transformation, serialization, and deserialization between objects and classes. +- [class-validator](https://github.com/typestack/class-validator) - Decorator-based property validation for classes. +- [json-difference](https://github.com/lukascivil/json-difference) - A simple way to find the difference between two objects or json diff. +- [tslog](https://github.com/fullstack-build/tslog) - Universal Logger for TypeScript and JavaScript. + +## License + +MIT - [crashmax](https://github.com/crashmax-dev) diff --git a/packages/stenodb/package.json b/packages/stenodb/package.json index 35c103c..f5fc843 100644 --- a/packages/stenodb/package.json +++ b/packages/stenodb/package.json @@ -1,7 +1,7 @@ { "name": "stenodb", - "version": "1.0.0", - "description": "stenodb", + "description": "✍ Easy to use local JSON database", + "version": "2.0.0", "type": "module", "files": [ "dist" @@ -12,32 +12,62 @@ "node": [ "./dist/node.d.ts" ], + "node/types": [ + "./dist/node-types.d.ts" + ], "browser": [ "./dist/browser.d.ts" + ], + "browser/types": [ + "./dist/browser-types.d.ts" ] } }, "exports": { ".": "./dist/index.js", "./node": "./dist/node.js", - "./browser": "./dist/browser.js" + "./node/types": "./dist/node-types.js", + "./browser": "./dist/browser.js", + "./browser/types": "./dist/browser-types.js" + }, + "author": { + "name": "Vitalij Ryndin", + "email": "sys@crashmax.ru", + "url": "https://crashmax.ru" }, + "license": "MIT", + "homepage": "https://github.com/crashmax-dev/stenodb#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/crashmax-dev/stenodb.git" + }, + "bugs": { + "url": "https://github.com/crashmax-dev/stenodb/issues" + }, + "keywords": [ + "db", + "database", + "browser", + "local", + "localStorage", + "sessionStorage", + "class-transformer", + "JSON", + "ESM" + ], "scripts": { "dev": "tsc --watch", "build": "del-cli dist && tsc", "prepublishOnly": "pnpm build" }, "dependencies": { - "class-transformer": "0.5.1", - "json-difference": "1.9.1", - "picocolors": "1.0.0", - "steno": "3.0.0", - "winston": "3.8.2" + "@stenodb/browser": "workspace:2.0.0", + "@stenodb/node": "workspace:2.0.0" }, "peerDependencies": { "class-transformer": ">=0.5.0" }, "engines": { - "node": ">=16" + "node": ">=14.16" } } diff --git a/packages/stenodb/src/browser-types.ts b/packages/stenodb/src/browser-types.ts new file mode 100644 index 0000000..360e049 --- /dev/null +++ b/packages/stenodb/src/browser-types.ts @@ -0,0 +1 @@ +export * from '@stenodb/browser/types' diff --git a/packages/stenodb/src/browser.ts b/packages/stenodb/src/browser.ts index 40c611b..e90b711 100644 --- a/packages/stenodb/src/browser.ts +++ b/packages/stenodb/src/browser.ts @@ -1,2 +1 @@ -export { LocalStorage, SessionStorage } from './browser/adapter.js' -export { BrowserProvider } from './browser/provider.js' +export * from '@stenodb/browser' diff --git a/packages/stenodb/src/browser/adapter.ts b/packages/stenodb/src/browser/adapter.ts deleted file mode 100644 index 4b5f198..0000000 --- a/packages/stenodb/src/browser/adapter.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { parseData } from '../helpers.js' -import type { Steno } from '../types.js' - -export class BrowserStorage implements Steno.SyncAdapter { - #name: string - #storage: Storage - #data: T | null = null - - constructor(name: string, storage: Storage) { - this.#name = name - this.#storage = storage - } - - read(): T | null { - const data = this.#storage.getItem(this.#name) - if (!data) return null - - try { - this.#data = parseData(data).toJSON() as T - } catch (err) { - throw err - } - - return this.#data - } - - write(data: T | null): void { - this.#data = data - this.#storage.setItem(this.#name, parseData(data).toString()) - } - - reset(initialData: T): void { - this.#storage.removeItem(this.#name) - this.write(initialData) - } - - exists(): boolean { - return this.read() !== null - } -} - -export class LocalStorage extends BrowserStorage { - constructor(name: string) { - super(name, localStorage) - } -} - -export class SessionStorage extends BrowserStorage { - constructor(name: string) { - super(name, sessionStorage) - } -} diff --git a/packages/stenodb/src/browser/database.ts b/packages/stenodb/src/browser/database.ts deleted file mode 100644 index 72f1ab7..0000000 --- a/packages/stenodb/src/browser/database.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { plainToClass } from 'class-transformer' -import type { Steno } from '../types.js' - -export class BrowserDatabase { - #adapter: Steno.BrowserAdapter - #entity: Steno.Entity - - data: T | null = null - initialData: T | null - - constructor(adapter: Steno.BrowserAdapter, entity: Steno.Entity) { - this.#adapter = adapter - - // TODO: validate entity - this.#entity = entity - } - - read(): T | null { - this.data = this.#adapter.read() - - if (!this.data && this.initialData) { - this.data = this.initialData - this.write() - } - - this.data = plainToClass(this.#entity, this.data) - return this.data - } - - write(): void { - this.#adapter.write(this.data) - } - - reset(): void { - if (!this.initialData) return - this.#adapter.reset(plainToClass(this.#entity, this.initialData)) - this.read() - } - - exists(): boolean { - return this.#adapter.exists() - } -} diff --git a/packages/stenodb/src/browser/provider.ts b/packages/stenodb/src/browser/provider.ts deleted file mode 100644 index ed16e8b..0000000 --- a/packages/stenodb/src/browser/provider.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { BrowserDatabase } from './database.js' -import type { Steno } from '../types.js' - -export class BrowserProvider extends BrowserDatabase { - constructor({ - adapter, - entity, - initialData = null - }: Omit, 'name'>) { - super(adapter, entity) - this.initialData ||= initialData - this.read() - } -} diff --git a/packages/stenodb/src/directory.ts b/packages/stenodb/src/directory.ts deleted file mode 100644 index fd854f4..0000000 --- a/packages/stenodb/src/directory.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { mkdir, readFile, rmSync } from 'node:fs' -import { join } from 'node:path' -import { Writer } from 'steno' -import { parseData } from './helpers.js' -import type { Logger } from './logger.js' - -export class DirectoryProvider { - #databasePath: string - #temporaryDirectory: string - #logger: Logger - - constructor(databasePath: string) { - this.#databasePath = databasePath - this.#temporaryDirectory = join(this.#databasePath, 'temp') - - mkdir(this.#temporaryDirectory, { recursive: true }, (err) => { - if (err) throw err - }) - } - - setLogger(logger: Logger): void { - this.#logger = logger - } - - removeFile(file: string, size = 0): void { - readFile(file, (err, buffer) => { - if (err) return - - if (size > 0 || buffer.byteLength === size) { - rmSync(file) - this.#logger.info(`Removed database: ${file}`) - } - }) - } - - databaseFilePath(filename: string): string { - return join(this.#databasePath, `${filename}.json`) - } - - temporaryFilePath(filename: string): string { - return join(this.#temporaryDirectory, `${filename}-${Date.now()}.json`) - } - - createTempFile(filename: string, data: T) { - const tempFile = this.temporaryFilePath(filename) - const tempFileWriter = new Writer(tempFile) - tempFileWriter.write(parseData(data).toString()) - } -} diff --git a/packages/stenodb/src/entity.ts b/packages/stenodb/src/entity.ts deleted file mode 100644 index 38cc520..0000000 --- a/packages/stenodb/src/entity.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { Logger, LoggerProvider } from './logger.js' -import type { Steno } from './types.js' - -export class EntityProvider { - #entities = new Map() - #logger: Logger - - constructor(logger: LoggerProvider) { - this.#logger = logger.createLogger('entity') - } - - addEntity(name: string, entity: Steno.Entity): void { - const existEntity = this.getEntity(name) - if (existEntity || typeof entity !== 'function') return - - this.#entities.set(name, entity) - this.#logger.info(`Entity "${entity.name}" register for "${name}" table.`) - } - - getEntity(name: string): Steno.Entity | undefined { - return this.#entities.get(name) - } -} - -export class EntityError extends Error { - constructor(name: string) { - super() - this.message = `EntityError: Entity not registered for ${name} table.` - } -} diff --git a/packages/stenodb/src/logger.ts b/packages/stenodb/src/logger.ts deleted file mode 100644 index eb458b4..0000000 --- a/packages/stenodb/src/logger.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { join } from 'node:path' -import pico from 'picocolors' -import winston, { createLogger } from 'winston' -import type { Steno } from './types.js' - -export class LoggerProvider { - #path: string - #options: Steno.LoggerProviderOptions - - #timestampFormatter = winston.format.timestamp({ - format: 'YYYY/MM/DD HH:mm:ss' - }) - - #consoleFormatter = winston.format.printf((info) => { - const timestamp = this.coloredTimestamp(info.timestamp) - const level = this.coloredLevel(info.level) - const message = this.coloredMessage(info.message) - const args = info.args[0] ? this.coloredJSON(info.args[0]) : '' - return `${timestamp} ${level} ${message}${args}` - }) - - #fileFormatter = winston.format.printf((info) => { - const { timestamp, level, message } = info - const args = info.args[0] - ? `\n${JSON.stringify(info.args[0], null, 2)}` - : '' - return `[${timestamp}] ${level.toUpperCase()} ${message}${args}` - }) - - constructor(path: string, options?: Steno.LoggerProviderOptions) { - this.#path = path - this.#options = options ?? { enabled: false } - } - - private coloredTimestamp(timestamp: string): string { - return pico.gray(`[${timestamp}]`) - } - - private coloredMessage(message: string): string { - return pico.white(message) - } - - private coloredLevel(level: string): string { - level = level.toUpperCase() - switch (level) { - case 'INFO': - return pico.green(level) - case 'WARN': - return pico.yellow(level) - case 'ERROR': - return pico.red(level) - default: - return level - } - } - - private coloredJSON(json: any): string { - return `\n${pico.cyan(JSON.stringify(json, null, 2))}` - } - - createLogger(name: string) { - const logger = createLogger({ - level: 'silly', - silent: !this.#options.enabled, - format: winston.format.json(), - transports: [ - new winston.transports.Console({ - level: 'verbose', - format: winston.format.combine( - this.#timestampFormatter, - this.#consoleFormatter - ) - }), - new winston.transports.File({ - dirname: join(this.#path, 'logs'), - filename: `${name}.log`, - format: winston.format.combine( - this.#timestampFormatter, - this.#fileFormatter - ) - }) - ] - }) - - return new Logger(logger) - } -} - -export class Logger { - #logger: winston.Logger - - constructor(logger: winston.Logger) { - this.#logger = logger - } - - info(message: string, ...args: any[]): void { - this.#logger.info(message, { args }) - } - - warn(message: string, ...args: any[]): void { - this.#logger.warn(message, { args }) - } - - error(message: string, ...args: any[]): void { - this.#logger.error(message, { args }) - } -} diff --git a/packages/stenodb/src/node-types.ts b/packages/stenodb/src/node-types.ts new file mode 100644 index 0000000..9a6dd42 --- /dev/null +++ b/packages/stenodb/src/node-types.ts @@ -0,0 +1 @@ +export * from '@stenodb/node/types' diff --git a/packages/stenodb/src/node.ts b/packages/stenodb/src/node.ts index 3e9f714..da06ff5 100644 --- a/packages/stenodb/src/node.ts +++ b/packages/stenodb/src/node.ts @@ -1,2 +1 @@ -export { NodeProvider } from './node/provider.js' -export { AsyncWriter, SyncWriter } from './node/adapter.js' +export * from '@stenodb/node' diff --git a/packages/stenodb/src/node/adapter.ts b/packages/stenodb/src/node/adapter.ts deleted file mode 100644 index 71c2598..0000000 --- a/packages/stenodb/src/node/adapter.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { readFile, readFileSync } from 'node:fs' -import { readFile as readFileAsync } from 'node:fs/promises' -import { Writer } from 'steno' -import { parseData } from '../helpers.js' -import type { DirectoryProvider } from '../directory.js' -import type { Steno } from '../types.js' - -export class SyncWriter implements Steno.SyncAdapter { - #filename: string - #path: string - #directory: DirectoryProvider - #writer: Writer - #data: T | null = null - - constructor(filename: string, directory: DirectoryProvider) { - this.#filename = filename - this.#path = directory.databaseFilePath(this.#filename) - this.#directory = directory - this.#writer = new Writer(this.#path) - } - - read(): T | null { - try { - const file = readFileSync(this.#path, 'utf-8') - this.#data = parseData(file).toJSON() - } catch (err) { - if ((err as NodeJS.ErrnoException).code === 'ENOENT') { - return null - } - - throw err - } - - return this.#data - } - - write(data: T | null): void { - this.#data = data - this.#writer.write(parseData(data).toString()) - } - - reset(initialData: T): void { - readFile(this.#path, (err, buffer) => { - if (err) throw err - this.#directory.createTempFile(this.#filename, parseData(buffer).toJSON()) - }) - - this.write(initialData) - } - - exists(): boolean { - return this.read() !== null - } -} - -export class AsyncWriter implements Steno.AsyncAdapter { - #filename: string - #path: string - #directory: DirectoryProvider - #writer: Writer - #data: T | null = null - - constructor(filename: string, directory: DirectoryProvider) { - this.#filename = filename - this.#path = directory.databaseFilePath(this.#filename) - this.#directory = directory - this.#writer = new Writer(this.#path) - } - - async read(): Promise { - try { - const file = await readFileAsync(this.#filename, 'utf-8') - this.#data = JSON.parse(file) as T - } catch (err) { - if ((err as NodeJS.ErrnoException).code === 'ENOENT') { - return null - } - - throw err - } - - return this.#data - } - - async write(data: T | null): Promise { - this.#data = data - return this.#writer.write(parseData(data).toString()) - } - - async reset(initialData: T): Promise { - try { - const data = await readFileAsync(this.#path) - this.#directory.createTempFile(this.#filename, data) - return this.write(initialData) - } catch (err) { - if ((err as NodeJS.ErrnoException).code === 'ENOENT') { - return this.write(initialData) - } - - throw err - } - } - - async exists(): Promise { - return (await this.read()) !== null - } -} diff --git a/packages/stenodb/src/node/database.ts b/packages/stenodb/src/node/database.ts deleted file mode 100644 index a097768..0000000 --- a/packages/stenodb/src/node/database.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { plainToClass } from 'class-transformer' -import { EntityError } from '../entity.js' -import { getDifferenceData } from '../helpers.js' -import type { DirectoryProvider } from '../directory.js' -import type { Logger } from '../logger.js' -import type { Steno } from '../types.js' -import type { SyncWriter } from './adapter.js' - -export class NodeAdapter { - // #adapter: Steno.NodeAdapter - #adapter: SyncWriter - #name: string - #directory: DirectoryProvider - #entity: Steno.Entity - #logger: Logger - - data: T | null = null - initialData: T | null - - constructor({ - name, - directory, - entity, - logger, - adapter - }: Steno.NodeAdapterOptions) { - if (!entity) { - throw new EntityError(name) - } - - const file = directory.databaseFilePath(name) - directory.removeFile(file) - - this.#name = name - this.#directory = directory - this.#adapter = adapter - this.#entity = entity - this.#logger = logger.createLogger(name) - } - - read(): T { - this.data = this.#adapter.read() - - if (!this.data && this.initialData) { - this.#logger.info( - `Initializing database: ${this.#directory.databaseFilePath( - this.#name - )}`, - this.initialData - ) - this.data = this.initialData - this.#adapter.write(this.data) - } - - this.data = plainToClass(this.#entity, this.data) - return this.data - } - - write(): void { - const diffData = getDifferenceData(this.data, this.#adapter.read()) - const databasePath = this.#directory.databaseFilePath(this.#name) - this.#logger.info( - `Writing database: ${databasePath}`, - diffData ?? 'No changes' - ) - this.#adapter.write(this.data) - } - - reset(): void { - if (!this.initialData) return - this.#adapter.reset(plainToClass(this.#entity, this.initialData)) - this.read() - this.#logger.info( - `Resetting database: ${this.#directory.databaseFilePath(this.#name)}`, - this.data - ) - } - - exists(): boolean { - return this.#adapter.exists() - } -} diff --git a/packages/stenodb/src/node/provider.ts b/packages/stenodb/src/node/provider.ts deleted file mode 100644 index b65a802..0000000 --- a/packages/stenodb/src/node/provider.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { sep } from 'node:path' -import { DirectoryProvider } from '../directory.js' -import { EntityProvider } from '../entity.js' -import { LoggerProvider } from '../logger.js' -import { SyncWriter } from './adapter.js' -import { NodeAdapter } from './database.js' -import type { Logger } from '../logger.js' -import type { Steno } from '../types.js' - -export class NodeProvider { - #directoryProvider: DirectoryProvider - #loggerProvider: LoggerProvider - #databaseLogger: Logger - #entity: EntityProvider - - constructor({ path, logger }: Steno.DatabaseProviderOptions) { - this.#directoryProvider = new DirectoryProvider(path) - this.#loggerProvider = new LoggerProvider(path, logger) - - this.#entity = new EntityProvider(this.#loggerProvider) - const databaseFolder = path.split(sep).pop() ?? 'database' - this.#databaseLogger = this.#loggerProvider.createLogger(databaseFolder) - this.#directoryProvider.setLogger(this.#databaseLogger) - } - - createDatabase({ - name, - entity, - initialData = null - }: Steno.DatabaseOptions): NodeAdapter { - this.#entity.addEntity(name, entity) - - // TODO: add support for AsyncWriter - const adapter = new SyncWriter(name, this.#directoryProvider) - const db = new NodeAdapter({ - name, - adapter, - entity: this.#entity.getEntity(name), - directory: this.#directoryProvider, - logger: this.#loggerProvider - }) - - db.initialData ||= initialData - db.read() - - return db - } -} diff --git a/packages/stenodb/src/types.ts b/packages/stenodb/src/types.ts deleted file mode 100644 index 1fda9bd..0000000 --- a/packages/stenodb/src/types.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { LocalStorage, SessionStorage } from './browser/adapter.js' -import type { DirectoryProvider } from './directory.js' -import type { LoggerProvider } from './logger.js' -import type { AsyncWriter, SyncWriter } from './node/adapter.js' -import type { ClassConstructor } from 'class-transformer' - -export declare namespace Steno { - export interface NodeAdapterOptions { - name: string - entity: Entity | undefined - logger: LoggerProvider - directory: DirectoryProvider - // adapter: NodeAdapter - adapter: SyncWriter - } - - export interface DatabaseProviderOptions { - path: string - logger?: LoggerProviderOptions - } - - export interface DatabaseOptions { - name: string - entity: Entity - // adapter: NodeAdapter - initialData?: T | null - } - - export interface BrowserDatabaseOptions extends DatabaseOptions { - adapter: BrowserAdapter - } - - export interface LoggerProviderOptions { - enabled: boolean - } - - export interface SyncAdapter { - read(): T | null - write(data: T | null): void - reset(initialData: T): void - exists(): boolean - } - - export interface AsyncAdapter { - read(): Promise - write(data: T | null): Promise - reset(initialData: T): Promise - exists(): Promise - } - - export type Entity = ClassConstructor - export type NodeAdapter = SyncWriter | AsyncWriter - export type BrowserAdapter = LocalStorage | SessionStorage -} diff --git a/packages/stenodb/tsconfig.json b/packages/stenodb/tsconfig.json index 4344557..43493c0 100644 --- a/packages/stenodb/tsconfig.json +++ b/packages/stenodb/tsconfig.json @@ -2,9 +2,7 @@ "extends": "@crashmax/tsconfig", "compilerOptions": { "moduleResolution": "NodeNext", - "outDir": "dist", - "strictNullChecks": true, - "noPropertyAccessFromIndexSignature": false + "outDir": "dist" }, "include": [ "src" diff --git a/packages/utils/README.md b/packages/utils/README.md new file mode 100644 index 0000000..18c5461 --- /dev/null +++ b/packages/utils/README.md @@ -0,0 +1 @@ +# @stenodb/utils diff --git a/packages/utils/package.json b/packages/utils/package.json new file mode 100644 index 0000000..439e898 --- /dev/null +++ b/packages/utils/package.json @@ -0,0 +1,26 @@ +{ + "name": "@stenodb/utils", + "version": "2.0.0", + "type": "module", + "files": [ + "dist" + ], + "types": "dist", + "exports": { + ".": "./dist/index.js" + }, + "scripts": { + "dev": "tsc --watch", + "build": "del-cli dist && tsc", + "prepublishOnly": "pnpm build" + }, + "dependencies": { + "json-difference": "1.9.1" + }, + "devDependencies": { + "@types/node": "18.11.19" + }, + "engines": { + "node": ">=14.16" + } +} diff --git a/packages/stenodb/src/helpers.ts b/packages/utils/src/index.ts similarity index 100% rename from packages/stenodb/src/helpers.ts rename to packages/utils/src/index.ts diff --git a/packages/utils/tsconfig.json b/packages/utils/tsconfig.json new file mode 100644 index 0000000..43493c0 --- /dev/null +++ b/packages/utils/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@crashmax/tsconfig", + "compilerOptions": { + "moduleResolution": "NodeNext", + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1e0c4cd..d11085d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,59 +6,57 @@ importers: specifiers: '@crashmax/prettier-config': 2.2.1 '@crashmax/tsconfig': 1.0.2 - '@types/node': 18.11.18 cross-env: 7.0.3 del-cli: 5.0.0 nodemon: 2.0.20 ts-node: 10.9.1 tsx: 3.12.2 - turbo: ^1.7.0 - typescript: 4.9.4 + turbo: 1.7.2 + typescript: 4.9.5 devDependencies: '@crashmax/prettier-config': 2.2.1_za6dmrbiogn3z6m2plsv3qsi6m '@crashmax/tsconfig': 1.0.2 - '@types/node': 18.11.18 cross-env: 7.0.3 del-cli: 5.0.0 nodemon: 2.0.20 - ts-node: 10.9.1_awa2wsr5thmg3i7jqycphctjfq + ts-node: 10.9.1_qqdszkrtcshgbphghj7vnvrrby tsx: 3.12.2 - turbo: 1.7.0 - typescript: 4.9.4 + turbo: 1.7.2 + typescript: 4.9.5 examples/with-browser: specifiers: + '@stenodb/browser': workspace:* '@zero-dependency/dom': 0.12.0 class-transformer: 0.5.1 reflect-metadata: 0.1.13 - stenodb: workspace:* - typescript: 4.9.4 - vite: 4.0.4 + typescript: 4.9.5 + vite: 4.1.1 dependencies: + '@stenodb/browser': link:../../packages/browser '@zero-dependency/dom': 0.12.0 class-transformer: 0.5.1 reflect-metadata: 0.1.13 - stenodb: link:../../packages/stenodb devDependencies: - typescript: 4.9.4 - vite: 4.0.4 + typescript: 4.9.5 + vite: 4.1.1 - examples/with-lodash: + examples/with-browser-lodash: specifiers: + '@stenodb/browser': workspace:* '@types/lodash': 4.14.191 '@zero-dependency/dom': 0.12.0 class-transformer: 0.5.1 lodash: 4.17.21 reflect-metadata: 0.1.13 - stenodb: workspace:* typescript: 4.9.4 vite: 4.0.4 dependencies: + '@stenodb/browser': link:../../packages/browser '@zero-dependency/dom': 0.12.0 class-transformer: 0.5.1 lodash: 4.17.21 reflect-metadata: 0.1.13 - stenodb: link:../../packages/stenodb devDependencies: '@types/lodash': 4.14.191 typescript: 4.9.4 @@ -66,27 +64,73 @@ importers: examples/with-node: specifiers: + '@stenodb/node': workspace:* + '@types/node': 18.11.19 class-transformer: 0.5.1 reflect-metadata: 0.1.13 - stenodb: workspace:* dependencies: + '@stenodb/node': link:../../packages/node class-transformer: 0.5.1 reflect-metadata: 0.1.13 - stenodb: link:../../packages/stenodb + devDependencies: + '@types/node': 18.11.19 - packages/stenodb: + examples/with-node-lodash: specifiers: + '@stenodb/node': workspace:* + '@types/lodash': 4.14.191 + '@types/node': 18.11.19 + class-transformer: 0.5.1 + lodash: 4.17.21 + reflect-metadata: 0.1.13 + dependencies: + '@stenodb/node': link:../../packages/node + class-transformer: 0.5.1 + lodash: 4.17.21 + reflect-metadata: 0.1.13 + devDependencies: + '@types/lodash': 4.14.191 + '@types/node': 18.11.19 + + packages/browser: + specifiers: + '@stenodb/utils': workspace:2.0.0 + class-transformer: 0.5.1 + dependencies: + '@stenodb/utils': link:../utils + class-transformer: 0.5.1 + + packages/node: + specifiers: + '@stenodb/utils': workspace:2.0.0 + '@types/node': 18.11.19 class-transformer: 0.5.1 - json-difference: 1.9.1 - picocolors: 1.0.0 steno: 3.0.0 - winston: 3.8.2 dependencies: + '@stenodb/utils': link:../utils class-transformer: 0.5.1 - json-difference: 1.9.1 - picocolors: 1.0.0 steno: 3.0.0 - winston: 3.8.2 + devDependencies: + '@types/node': 18.11.19 + + packages/stenodb: + specifiers: + '@stenodb/browser': workspace:2.0.0 + '@stenodb/node': workspace:2.0.0 + class-transformer: '>=0.5.0' + dependencies: + '@stenodb/browser': link:../browser + '@stenodb/node': link:../node + class-transformer: 0.5.1 + + packages/utils: + specifiers: + '@types/node': 18.11.19 + json-difference: 1.9.1 + dependencies: + json-difference: 1.9.1 + devDependencies: + '@types/node': 18.11.19 packages: @@ -101,7 +145,7 @@ packages: /@augment-vir/common/6.4.0: resolution: {integrity: sha512-UA66AC3eFv5B43MvO0iz9BheW/rjzZNK+g1eodiIl9W5tfBuQ7J/XsGRh08GJu3iDUyRu8aae/iqLHorrweacg==} dependencies: - type-fest: 3.5.3 + type-fest: 3.5.4 dev: true /@babel/code-frame/7.18.6: @@ -111,8 +155,8 @@ packages: '@babel/highlight': 7.18.6 dev: true - /@babel/compat-data/7.20.10: - resolution: {integrity: sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==} + /@babel/compat-data/7.20.14: + resolution: {integrity: sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==} engines: {node: '>=6.9.0'} dev: true @@ -122,11 +166,11 @@ packages: dependencies: '@ampproject/remapping': 2.2.0 '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.7 + '@babel/generator': 7.20.14 '@babel/helper-compilation-targets': 7.20.7_@babel+core@7.20.12 '@babel/helper-module-transforms': 7.20.11 '@babel/helpers': 7.20.13 - '@babel/parser': 7.20.13 + '@babel/parser': 7.20.15 '@babel/template': 7.20.7 '@babel/traverse': 7.20.13 '@babel/types': 7.20.7 @@ -139,8 +183,8 @@ packages: - supports-color dev: true - /@babel/generator/7.20.7: - resolution: {integrity: sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==} + /@babel/generator/7.20.14: + resolution: {integrity: sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.20.7 @@ -154,10 +198,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.20.10 + '@babel/compat-data': 7.20.14 '@babel/core': 7.20.12 '@babel/helper-validator-option': 7.18.6 - browserslist: 4.21.4 + browserslist: 4.21.5 lru-cache: 5.1.1 semver: 6.3.0 dev: true @@ -254,8 +298,8 @@ packages: js-tokens: 4.0.0 dev: true - /@babel/parser/7.20.13: - resolution: {integrity: sha512-gFDLKMfpiXCsjt4za2JA9oTMn70CeseCehb11kRZgvd7+F67Hih3OHOK24cRrWECJ/ljfPGac6ygXAs/C8kIvw==} + /@babel/parser/7.20.15: + resolution: {integrity: sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==} engines: {node: '>=6.0.0'} hasBin: true dependencies: @@ -267,7 +311,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/parser': 7.20.13 + '@babel/parser': 7.20.15 '@babel/types': 7.20.7 dev: true @@ -276,12 +320,12 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.7 + '@babel/generator': 7.20.14 '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-function-name': 7.19.0 '@babel/helper-hoist-variables': 7.18.6 '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.20.13 + '@babel/parser': 7.20.15 '@babel/types': 7.20.7 debug: 4.3.4 globals: 11.12.0 @@ -298,11 +342,6 @@ packages: to-fast-properties: 2.0.0 dev: true - /@colors/colors/1.5.0: - resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} - engines: {node: '>=0.1.90'} - dev: false - /@crashmax/prettier-config/2.2.1_za6dmrbiogn3z6m2plsv3qsi6m: resolution: {integrity: sha512-sWOjTuyQPc49hm+9MvDET7zoy7nkiLxRVYuWhalmW+vwE1ALtyBMo3HXfoAxcLOvi7OnpCNSNdd/TAJnAqT7RQ==} peerDependencies: @@ -327,14 +366,6 @@ packages: '@jridgewell/trace-mapping': 0.3.9 dev: true - /@dabh/diagnostics/2.0.3: - resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==} - dependencies: - colorspace: 1.1.4 - enabled: 2.0.0 - kuler: 2.0.0 - dev: false - /@esbuild-kit/cjs-loader/2.4.1: resolution: {integrity: sha512-lhc/XLith28QdW0HpHZvZKkorWgmCNT7sVelMHDj3HFdTfdqkwEKvT+aXVQtNAmCC39VJhunDkWhONWB7335mg==} dependencies: @@ -582,8 +613,8 @@ packages: optional: true dependencies: '@babel/core': 7.20.12 - '@babel/generator': 7.20.7 - '@babel/parser': 7.20.13 + '@babel/generator': 7.20.14 + '@babel/parser': 7.20.15 '@babel/traverse': 7.20.13 '@babel/types': 7.20.7 javascript-natural-sort: 0.7.1 @@ -684,8 +715,8 @@ packages: resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} dev: true - /@types/node/18.11.18: - resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==} + /@types/node/18.11.19: + resolution: {integrity: sha512-YUgMWAQBWLObABqrvx8qKO1enAvBUdjZOAWQ5grBAkp5LQv45jBvYKZ3oFS9iKRCQyFjqw6iuEa1vmFqtxYLZw==} dev: true /@types/normalize-package-data/2.4.1: @@ -711,8 +742,8 @@ packages: engines: {node: '>=0.4.0'} dev: true - /acorn/8.8.1: - resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==} + /acorn/8.8.2: + resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} engines: {node: '>=0.4.0'} hasBin: true dev: true @@ -749,10 +780,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /async/3.2.4: - resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} - dev: false - /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true @@ -776,15 +803,15 @@ packages: fill-range: 7.0.1 dev: true - /browserslist/4.21.4: - resolution: {integrity: sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==} + /browserslist/4.21.5: + resolution: {integrity: sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001449 - electron-to-chromium: 1.4.284 - node-releases: 2.0.8 - update-browserslist-db: 1.0.10_browserslist@4.21.4 + caniuse-lite: 1.0.30001450 + electron-to-chromium: 1.4.285 + node-releases: 2.0.9 + update-browserslist-db: 1.0.10_browserslist@4.21.5 dev: true /buffer-from/1.1.2: @@ -806,8 +833,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite/1.0.30001449: - resolution: {integrity: sha512-CPB+UL9XMT/Av+pJxCKGhdx+yg1hzplvFJQlJ2n68PyQGMz9L/E2zCyLdOL8uasbouTUgnPl+y0tccI/se+BEw==} + /caniuse-lite/1.0.30001450: + resolution: {integrity: sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew==} dev: true /chalk/2.4.2: @@ -849,34 +876,11 @@ packages: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 + dev: true /color-name/1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - - /color-name/1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: false - - /color-string/1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - dev: false - - /color/3.2.1: - resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} - dependencies: - color-convert: 1.9.3 - color-string: 1.9.1 - dev: false - - /colorspace/1.1.4: - resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==} - dependencies: - color: 3.2.1 - text-hex: 1.0.0 - dev: false + dev: true /concat-map/0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -984,14 +988,10 @@ packages: path-type: 4.0.0 dev: true - /electron-to-chromium/1.4.284: - resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==} + /electron-to-chromium/1.4.285: + resolution: {integrity: sha512-47o4PPgxfU1KMNejz+Dgaodf7YTcg48uOfV1oM6cs3adrl2+7R+dHkt3Jpxqo0LRCbGJEzTKMUt0RdvByb/leg==} dev: true - /enabled/2.0.0: - resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} - dev: false - /error-ex/1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: @@ -1270,10 +1270,6 @@ packages: reusify: 1.0.4 dev: true - /fecha/4.2.3: - resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} - dev: false - /fill-range/7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} @@ -1289,10 +1285,6 @@ packages: path-exists: 4.0.0 dev: true - /fn.name/1.1.0: - resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} - dev: false - /fs.realpath/1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true @@ -1403,15 +1395,12 @@ packages: /inherits/2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true /is-arrayish/0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true - /is-arrayish/0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - dev: false - /is-binary-path/2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -1457,11 +1446,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /is-stream/2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - dev: false - /isexe/2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true @@ -1500,10 +1484,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /kuler/2.0.0: - resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} - dev: false - /lines-and-columns/1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true @@ -1527,16 +1507,6 @@ packages: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: false - /logform/2.4.2: - resolution: {integrity: sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw==} - dependencies: - '@colors/colors': 1.5.0 - fecha: 4.2.3 - ms: 2.1.3 - safe-stable-stringify: 2.4.2 - triple-beam: 1.3.0 - dev: false - /lru-cache/5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -1621,6 +1591,7 @@ packages: /ms/2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true /nanoid/3.3.4: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} @@ -1628,8 +1599,8 @@ packages: hasBin: true dev: true - /node-releases/2.0.8: - resolution: {integrity: sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==} + /node-releases/2.0.9: + resolution: {integrity: sha512-2xfmOrRkGogbTK9R6Leda0DGiXeY3p2NJpy4+gNCffdUvV6mdEJnaDEic1i3Ec2djAo8jWYoJMR5PB0MSMpxUA==} dev: true /nodemon/2.0.20: @@ -1677,12 +1648,6 @@ packages: wrappy: 1.0.2 dev: true - /one-time/1.0.0: - resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} - dependencies: - fn.name: 1.1.0 - dev: false - /p-limit/3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -1740,6 +1705,7 @@ packages: /picocolors/1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true /picomatch/2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -1799,15 +1765,6 @@ packages: type-fest: 1.4.0 dev: true - /readable-stream/3.6.0: - resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} - engines: {node: '>= 6'} - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - dev: false - /readdirp/3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -1848,8 +1805,8 @@ packages: glob: 7.2.3 dev: true - /rollup/3.12.0: - resolution: {integrity: sha512-4MZ8kA2HNYahIjz63rzrMMRvDqQDeS9LoriJvMuV0V6zIGysP36e9t4yObUfwdT9h/szXoHQideICftcdZklWg==} + /rollup/3.13.0: + resolution: {integrity: sha512-HJwQtrXAc0AmyDohTJ/2c+Bx/sWPScJLlAUJ1kuD7rAkCro8Cr2SnVB2gVYBiSLxpgD2kZ24jbyXtG++GumrYQ==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: @@ -1862,15 +1819,6 @@ packages: queue-microtask: 1.2.3 dev: true - /safe-buffer/5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: false - - /safe-stable-stringify/2.4.2: - resolution: {integrity: sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==} - engines: {node: '>=10'} - dev: false - /semver/5.7.1: resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} hasBin: true @@ -1906,12 +1854,6 @@ packages: engines: {node: '>=8'} dev: true - /simple-swizzle/0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - dependencies: - is-arrayish: 0.3.2 - dev: false - /simple-update-notifier/1.1.0: resolution: {integrity: sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==} engines: {node: '>=8.10.0'} @@ -1963,21 +1905,11 @@ packages: resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==} dev: true - /stack-trace/0.0.10: - resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} - dev: false - /steno/3.0.0: resolution: {integrity: sha512-uZtn7Ht9yXLiYgOsmo8btj4+f7VxyYheMt8g6F1ANjyqByQXEE2Gygjgenp3otHH1TlHsS4JAaRGv5wJ1wvMNw==} engines: {node: '>=14.16'} dev: false - /string_decoder/1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - dependencies: - safe-buffer: 5.2.1 - dev: false - /strip-indent/4.0.0: resolution: {integrity: sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==} engines: {node: '>=12'} @@ -1997,10 +1929,6 @@ packages: engines: {node: '>= 0.4'} dev: true - /text-hex/1.0.0: - resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} - dev: false - /to-fast-properties/2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} @@ -2025,11 +1953,7 @@ packages: engines: {node: '>=12'} dev: true - /triple-beam/1.3.0: - resolution: {integrity: sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==} - dev: false - - /ts-node/10.9.1_awa2wsr5thmg3i7jqycphctjfq: + /ts-node/10.9.1_qqdszkrtcshgbphghj7vnvrrby: resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -2048,14 +1972,14 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.3 - '@types/node': 18.11.18 - acorn: 8.8.1 + '@types/node': 18.11.19 + acorn: 8.8.2 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.9.4 + typescript: 4.9.5 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 dev: true @@ -2071,65 +1995,65 @@ packages: fsevents: 2.3.2 dev: true - /turbo-darwin-64/1.7.0: - resolution: {integrity: sha512-hSGAueSf5Ko8J67mpqjpt9FsP6ePn1nMcl7IVPoJq5dHsgX3anCP/BPlexJ502bNK+87DDyhQhJ/LPSJXKrSYQ==} + /turbo-darwin-64/1.7.2: + resolution: {integrity: sha512-Sml3WR8MSu80W+gS8SnoKNImcDOlIX7zlvezzds65mW11yGniIFfZ18aKWGOm92Nj2SvXCQ2+UmyGghbFaHNmQ==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-darwin-arm64/1.7.0: - resolution: {integrity: sha512-BLLOW5W6VZxk5+0ZOj5AO1qjM0P5isIgjbEuyAl8lHZ4s9antUbY4CtFrspT32XxPTYoDl4UjviPMcSsbcl3WQ==} + /turbo-darwin-arm64/1.7.2: + resolution: {integrity: sha512-JnlgGLScboUJGJxvmSsF+5xkImEDTMPg2FHzX4n8AMB9az9ZlPQAMtc+xu4p6Xp9eaykKiV2RG81YS3H0fxDLA==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-linux-64/1.7.0: - resolution: {integrity: sha512-aw2qxmfZa+kT87SB3GNUoFimqEPzTlzlRqhPgHuAAT6Uf0JHnmebPt4K+ZPtDNl5yfVmtB05bhHPqw+5QV97Yg==} + /turbo-linux-64/1.7.2: + resolution: {integrity: sha512-vbLJw6ovG+lpiPqxniscBjljKJ2jbsHuKp8uK4j/wqgp68wAVKeAZW77GGDAUgDb88XH6Kvhh2hcizL+iWduww==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-linux-arm64/1.7.0: - resolution: {integrity: sha512-AJEx2jX+zO5fQtJpO3r6uhTabj4oSA5ZhB7zTs/rwu/XqoydsvStA4X8NDW4poTbOjF7DcSHizqwi04tSMzpJw==} + /turbo-linux-arm64/1.7.2: + resolution: {integrity: sha512-zLnuS8WdHonKL74KqOopOH/leBOWumlVGF8/8hldbDPq0mwY+6myRR5/5LdveB51rkG4UJh/sQ94xV67tjBoyw==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-windows-64/1.7.0: - resolution: {integrity: sha512-ewj7PPv2uxqv0r31hgnBa3E5qwUu7eyVRP5M1gB/TJXfSHduU79gbxpKCyxIZv2fL/N2/3U7EPOQPSZxBAoljA==} + /turbo-windows-64/1.7.2: + resolution: {integrity: sha512-oE5PMoXjmR09okvVzteFb6FjA6yo+nMsacsgKH2yLNq4sOrVo9tG98JkRurOv5+L6ZQ3yGXPxWHiqeH7hLkAVQ==} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /turbo-windows-arm64/1.7.0: - resolution: {integrity: sha512-LzjOUzveWkvTD0jP8DBMYiAnYemmydsvqxdSmsUapHHJkl6wKZIOQNSO7pxsy+9XM/1/+0f9Y9F9ZNl5lePTEA==} + /turbo-windows-arm64/1.7.2: + resolution: {integrity: sha512-mdTUJk23acRv5qxA/yEstYhM1VFenVE3FDrssxGRFq7S80smtCGK1xUd4BEDDzDlVXOqBohmM5jRh9516rcjPQ==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /turbo/1.7.0: - resolution: {integrity: sha512-cwympNwQNnQZ/TffBd8yT0i0O10Cf/hlxccCYgUcwhcGEb9rDjE5thDbHoHw1hlJQUF/5ua7ERJe7Zr0lNE/ww==} + /turbo/1.7.2: + resolution: {integrity: sha512-YR/x3GZEx0C1RV6Yvuw/HB1Ixx3upM6ZTTa4WqKz9WtLWN8u2g+u2h5KpG5YtjCS3wl/8zVXgHf2WiMK6KIghg==} hasBin: true requiresBuild: true optionalDependencies: - turbo-darwin-64: 1.7.0 - turbo-darwin-arm64: 1.7.0 - turbo-linux-64: 1.7.0 - turbo-linux-arm64: 1.7.0 - turbo-windows-64: 1.7.0 - turbo-windows-arm64: 1.7.0 + turbo-darwin-64: 1.7.2 + turbo-darwin-arm64: 1.7.2 + turbo-linux-64: 1.7.2 + turbo-linux-arm64: 1.7.2 + turbo-windows-64: 1.7.2 + turbo-windows-arm64: 1.7.2 dev: true /type-fest/1.4.0: @@ -2137,8 +2061,8 @@ packages: engines: {node: '>=10'} dev: true - /type-fest/3.5.3: - resolution: {integrity: sha512-V2+og4j/rWReWvaFrse3s9g2xvUv/K9Azm/xo6CjIuq7oeGqsoimC7+9/A3tfvNcbQf8RPSVj/HV81fB4DJrjA==} + /type-fest/3.5.4: + resolution: {integrity: sha512-/Je22Er4LPoln256pcLzj73MUmPrTWg8u4WB1RlxaDl0idJOfD1r259VtKOinp4xLJqJ9zYVMuWOun6Ssp7boA==} engines: {node: '>=14.16'} dev: true @@ -2148,25 +2072,27 @@ packages: hasBin: true dev: true + /typescript/4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + /undefsafe/2.0.5: resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} dev: true - /update-browserslist-db/1.0.10_browserslist@4.21.4: + /update-browserslist-db/1.0.10_browserslist@4.21.5: resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: - browserslist: 4.21.4 + browserslist: 4.21.5 escalade: 3.1.1 picocolors: 1.0.0 dev: true - /util-deprecate/1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - dev: false - /v8-compile-cache-lib/3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} dev: true @@ -2206,7 +2132,40 @@ packages: esbuild: 0.16.17 postcss: 8.4.21 resolve: 1.22.1 - rollup: 3.12.0 + rollup: 3.13.0 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /vite/4.1.1: + resolution: {integrity: sha512-LM9WWea8vsxhr782r9ntg+bhSFS06FJgCvvB0+8hf8UWtvaiDagKYWXndjfX6kGl74keHJUcpzrQliDXZlF5yg==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.16.17 + postcss: 8.4.21 + resolve: 1.22.1 + rollup: 3.13.0 optionalDependencies: fsevents: 2.3.2 dev: true @@ -2219,32 +2178,6 @@ packages: isexe: 2.0.0 dev: true - /winston-transport/4.5.0: - resolution: {integrity: sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==} - engines: {node: '>= 6.4.0'} - dependencies: - logform: 2.4.2 - readable-stream: 3.6.0 - triple-beam: 1.3.0 - dev: false - - /winston/3.8.2: - resolution: {integrity: sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==} - engines: {node: '>= 12.0.0'} - dependencies: - '@colors/colors': 1.5.0 - '@dabh/diagnostics': 2.0.3 - async: 3.2.4 - is-stream: 2.0.1 - logform: 2.4.2 - one-time: 1.0.0 - readable-stream: 3.6.0 - safe-stable-stringify: 2.4.2 - stack-trace: 0.0.10 - triple-beam: 1.3.0 - winston-transport: 4.5.0 - dev: false - /wrappy/1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true diff --git a/turbo.json b/turbo.json index e3b0bac..e9ec357 100644 --- a/turbo.json +++ b/turbo.json @@ -5,7 +5,8 @@ "cache": false }, "build": { - "outputs": ["dist/**"] + "outputs": ["dist/**"], + "dependsOn": ["^build"] } } }