diff --git a/.changeset/early-wolves-whisper.md b/.changeset/early-wolves-whisper.md new file mode 100644 index 0000000000..c9426ae4a6 --- /dev/null +++ b/.changeset/early-wolves-whisper.md @@ -0,0 +1,12 @@ +--- +"@effect/sql-sqlite-react-native": minor +"@effect/sql-sqlite-node": minor +"@effect/sql-sqlite-wasm": minor +"@effect/sql-sqlite-bun": minor +"@effect/sql-mysql2": minor +"@effect/sql-mssql": minor +"@effect/sql-pg": minor +"@effect/sql": minor +--- + +initial @effect/sql release diff --git a/.changeset/moody-candles-relax.md b/.changeset/moody-candles-relax.md new file mode 100644 index 0000000000..b9563430d6 --- /dev/null +++ b/.changeset/moody-candles-relax.md @@ -0,0 +1,5 @@ +--- +"effect": patch +--- + +don't run resolver if there are no incomplete requests diff --git a/.changeset/serious-glasses-own.md b/.changeset/serious-glasses-own.md new file mode 100644 index 0000000000..371ee1eb4e --- /dev/null +++ b/.changeset/serious-glasses-own.md @@ -0,0 +1,12 @@ +--- +"effect": patch +--- + +add String casing transformation apis + +- `snakeToCamel` +- `snakeToPascal` +- `snakeToKebab` +- `camelToSnake` +- `pascalToSnake` +- `kebabToSnake` diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a6ba9101cd..3101ff3abe 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,14 +1,24 @@ -/packages/effect/ @mikearnaldi -/packages/cli/ @IMax153 -/packages/experimental/ @tim-smart -/packages/opentelemetry/ @tim-smart -/packages/platform/ @tim-smart -/packages/platform-browser/ @tim-smart -/packages/platform-bun/ @tim-smart -/packages/platform-node/ @tim-smart -/packages/printer/ @IMax153 -/packages/printer-ansi/ @IMax153 -/packages/rpc/ @tim-smart -/packages/rpc-http/ @tim-smart -/packages/schema/ @gcanti -/packages/typeclass/ @gcanti +/packages/effect/ @mikearnaldi +/packages/cli/ @IMax153 +/packages/experimental/ @tim-smart +/packages/opentelemetry/ @tim-smart +/packages/platform/ @tim-smart +/packages/platform-browser/ @tim-smart +/packages/platform-bun/ @tim-smart +/packages/platform-node/ @tim-smart +/packages/platform-node-shared/ @tim-smart +/packages/printer/ @IMax153 +/packages/printer-ansi/ @IMax153 +/packages/rpc/ @tim-smart +/packages/rpc-http/ @tim-smart +/packages/schema/ @gcanti +/packages/sql/ @tim-smart +/packages/sql-mssql/ @tim-smart +/packages/sql-mysql2/ @tim-smart +/packages/sql-pg/ @tim-smart +/packages/sql-sqlite-bun/ @tim-smart +/packages/sql-sqlite-node/ @tim-smart +/packages/sql-sqlite-react-native/ @tim-smart +/packages/sql-sqlite-wasm/ @tim-smart +/packages/typeclass/ @gcanti +/packages/vitest/ @mikearnaldi diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 8358776381..eb6bb63fee 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -18,4 +18,4 @@ runs: node-version: ${{ inputs.node-version }} - name: Install dependencies shell: bash - run: pnpm install --ignore-scripts + run: pnpm install diff --git a/package.json b/package.json index 3e6e1bff3c..e35998ba85 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "clean": "node scripts/clean.mjs", "codegen": "pnpm --recursive --parallel run codegen", "build": "tsc -b tsconfig.build.json && pnpm --recursive --parallel run build", - "circular": "madge --extensions ts --circular --no-color --no-spinner packages/*/src", + "circular": "node scripts/circular.mjs", "test": "vitest", "coverage": "vitest --coverage", "check": "tsc -b tsconfig.json", diff --git a/packages/effect/src/String.ts b/packages/effect/src/String.ts index 02ae70760c..4c30cba7e6 100644 --- a/packages/effect/src/String.ts +++ b/packages/effect/src/String.ts @@ -624,6 +624,49 @@ export const stripMarginWith: { */ export const stripMargin = (self: string): string => stripMarginWith(self, "|") +/** + * @since 2.0.0 + */ +export const snakeToCamel = (self: string): string => { + let str = self[0] + for (let i = 1; i < self.length; i++) { + str += self[i] === "_" ? self[++i].toUpperCase() : self[i] + } + return str +} + +/** + * @since 2.0.0 + */ +export const snakeToPascal = (self: string): string => { + let str = self[0].toUpperCase() + for (let i = 1; i < self.length; i++) { + str += self[i] === "_" ? self[++i].toUpperCase() : self[i] + } + return str +} + +/** + * @since 2.0.0 + */ +export const snakeToKebab = (self: string): string => self.replace(/_/g, "-") + +/** + * @since 2.0.0 + */ +export const camelToSnake = (self: string): string => self.replace(/([A-Z])/g, "_$1").toLowerCase() + +/** + * @since 2.0.0 + */ +export const pascalToSnake = (self: string): string => + (self.slice(0, 1) + self.slice(1).replace(/([A-Z])/g, "_$1")).toLowerCase() + +/** + * @since 2.0.0 + */ +export const kebabToSnake = (self: string): string => self.replace(/-/g, "_") + class LinesIterator implements IterableIterator { private index: number private readonly length: number diff --git a/packages/effect/src/internal/dataSource.ts b/packages/effect/src/internal/dataSource.ts index 616c25eb72..a441ab241c 100644 --- a/packages/effect/src/internal/dataSource.ts +++ b/packages/effect/src/internal/dataSource.ts @@ -28,24 +28,24 @@ export const makeBatched = , R>( run: (requests: Array) => Effect.Effect ): RequestResolver.RequestResolver => new core.RequestResolverImpl( - (requests) => - requests.length > 1 ? - core.forEachSequentialDiscard(requests, (block) => - invokeWithInterrupt( - run( - block - .filter((_) => !_.state.completed) - .map((_) => _.request) - ), - block - )) : - (requests.length === 1 ? - run( - requests[0] - .filter((_) => !_.state.completed) - .map((_) => _.request) - ) : - core.unit) + (requests) => { + if (requests.length > 1) { + return core.forEachSequentialDiscard(requests, (block) => { + const filtered = block.filter((_) => !_.state.completed).map((_) => _.request) + if (filtered.length === 0) { + return core.unit + } + return invokeWithInterrupt(run(filtered), block) + }) + } else if (requests.length === 1) { + const filtered = requests[0].filter((_) => !_.state.completed).map((_) => _.request) + if (filtered.length === 0) { + return core.unit + } + return run(filtered) + } + return core.unit + } ) /** @internal */ diff --git a/packages/platform-node-shared/tsconfig.build.json b/packages/platform-node-shared/tsconfig.build.json index 37a515c3b6..c111670850 100644 --- a/packages/platform-node-shared/tsconfig.build.json +++ b/packages/platform-node-shared/tsconfig.build.json @@ -16,8 +16,6 @@ "outDir": "build/esm", "declarationDir": "build/dts", "stripInternal": true, - "types": [ - "node" - ] + "types": ["node"] } } diff --git a/packages/platform/src/Command.ts b/packages/platform/src/Command.ts index 3e7872100f..84ef8d0bd6 100644 --- a/packages/platform/src/Command.ts +++ b/packages/platform/src/Command.ts @@ -122,8 +122,8 @@ export const isCommand: (u: unknown) => u is Command = internal.isCommand * @category combinators */ export const env: { - (environment: Record): (self: Command) => Command - (self: Command, environment: Record): Command + (environment: Record): (self: Command) => Command + (self: Command, environment: Record): Command } = internal.env /** diff --git a/packages/platform/src/internal/command.ts b/packages/platform/src/internal/command.ts index a10867d53a..c5fbd84b5f 100644 --- a/packages/platform/src/internal/command.ts +++ b/packages/platform/src/internal/command.ts @@ -21,15 +21,21 @@ export const isCommand = (u: unknown): u is Command.Command => typeof u === "obj /** @internal */ export const env: { - (environment: Record): (self: Command.Command) => Command.Command - (self: Command.Command, environment: Record): Command.Command + (environment: Record): (self: Command.Command) => Command.Command + (self: Command.Command, environment: Record): Command.Command } = dual< - (environment: Record) => (self: Command.Command) => Command.Command, - (self: Command.Command, environment: Record) => Command.Command + (environment: Record) => (self: Command.Command) => Command.Command, + (self: Command.Command, environment: Record) => Command.Command >(2, (self, environment) => { switch (self._tag) { case "StandardCommand": { - return makeStandard({ ...self, env: HashMap.union(self.env, HashMap.fromIterable(Object.entries(environment))) }) + return makeStandard({ + ...self, + env: HashMap.union( + self.env, + HashMap.fromIterable(Object.entries(environment).filter(([v]) => v !== undefined)) + ) as HashMap.HashMap + }) } case "PipedCommand": { return pipeTo(env(self.left, environment), env(self.right, environment)) diff --git a/packages/sql-mssql/LICENSE b/packages/sql-mssql/LICENSE new file mode 100644 index 0000000000..7f6fe480f7 --- /dev/null +++ b/packages/sql-mssql/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023-present The Contributors + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/packages/sql-mssql/README.md b/packages/sql-mssql/README.md new file mode 100644 index 0000000000..6ae1c8de1b --- /dev/null +++ b/packages/sql-mssql/README.md @@ -0,0 +1,5 @@ +# Effect SQL - Microsoft SQL Server + +An @effect/sql implementation using the mssql `tedious` library. + +See here for more information: https://github.com/Effect-TS/effect/tree/main/packages/sql diff --git a/packages/sql-mssql/docgen.json b/packages/sql-mssql/docgen.json new file mode 100644 index 0000000000..f980a32f52 --- /dev/null +++ b/packages/sql-mssql/docgen.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../node_modules/@effect/docgen/schema.json", + "exclude": [ + "src/internal/**/*.ts" + ] +} diff --git a/packages/sql-mssql/examples/docker-compose.yaml b/packages/sql-mssql/examples/docker-compose.yaml new file mode 100644 index 0000000000..f4e69e9182 --- /dev/null +++ b/packages/sql-mssql/examples/docker-compose.yaml @@ -0,0 +1,22 @@ +services: + db: + environment: + ACCEPT_EULA: "Y" + SA_PASSWORD: "Sq1Fx_password" + # mssql server image isn't available for arm64 architecture, so we use azure-sql instead + # image: mcr.microsoft.com/azure-sql-edge:1.0.4 + # If you really want to use MS SQL Server, uncomment the following line + image: mcr.microsoft.com/mssql/server + ports: + - 1433:1433 + restart: always + healthcheck: + test: + [ + "CMD-SHELL", + "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Sq1Fx_password -Q 'SELECT 1' || exit 1", + ] + interval: 10s + retries: 10 + start_period: 10s + timeout: 3s diff --git a/packages/sql-mssql/examples/migrations.ts b/packages/sql-mssql/examples/migrations.ts new file mode 100644 index 0000000000..90dd1e7712 --- /dev/null +++ b/packages/sql-mssql/examples/migrations.ts @@ -0,0 +1,106 @@ +import * as DevTools from "@effect/experimental/DevTools" +import { NodeFileSystem } from "@effect/platform-node" +import * as Sql from "@effect/sql-mssql" +import { Config, Effect, Layer, Logger, LogLevel, Secret, String } from "effect" +import { pipe } from "effect/Function" +import { fileURLToPath } from "node:url" + +const peopleProcedure = pipe( + Sql.procedure.make("people_proc"), + Sql.procedure.param()("name", Sql.types.VarChar), + Sql.procedure.withRows<{ readonly id: number; readonly name: string }>(), + Sql.procedure.compile +) + +const program = Effect.gen(function*(_) { + const sql = yield* _(Sql.client.MssqlClient) + + yield* _( + sql` + CREATE OR ALTER PROC people_proc + @name VARCHAR(255) + AS + BEGIN + SELECT * FROM people WHERE name = @name + END + ` + ) + + // Insert + const [inserted] = yield* _( + sql`INSERT INTO ${sql("people")} ${ + sql.insert({ + name: "Tim", + createdAt: new Date() + }) + }` + ) + console.log(inserted) + + console.log( + yield* _( + Effect.all( + [ + sql`SELECT TOP 3 * FROM ${sql("people")}`, + sql`SELECT TOP 3 * FROM ${sql("people")}`.values, + sql`SELECT TOP 3 * FROM ${sql("people")}`.withoutTransform, + sql.call(peopleProcedure({ name: "Tim" })) + ], + { concurrency: "unbounded" } + ) + ) + ) + + console.log( + yield* _(sql` + UPDATE people + SET name = data.name + OUTPUT inserted.* + FROM ${sql.updateValues([{ ...inserted, name: "New name" }], "data")} + WHERE people.id = data.id + `) + ) + + console.log( + yield* _( + sql`SELECT TOP 3 * FROM ${sql("people")}`, + Effect.zipRight( + Effect.catchAllCause( + sql.withTransaction(Effect.die("fail")), + (_) => Effect.unit + ) + ), + Effect.zipRight( + sql.withTransaction(sql`SELECT TOP 3 * FROM ${sql("people")}`) + ), + sql.withTransaction + ) + ) +}) + +const SqlLive = Sql.migrator.layer({ + loader: Sql.migrator.fromFileSystem( + fileURLToPath(new URL("./migrations", import.meta.url)) + ) +}).pipe( + Layer.provideMerge( + Sql.client.layer({ + database: Config.succeed("msdb"), + server: Config.succeed("localhost"), + username: Config.succeed("sa"), + password: Config.succeed(Secret.fromString("Sq1Fx_password")), + transformQueryNames: Config.succeed(String.camelToSnake), + transformResultNames: Config.succeed(String.snakeToCamel) + }) + ), + Layer.provide(NodeFileSystem.layer), + Layer.provide(DevTools.layer()), + Layer.provide(Logger.minimumLogLevel(LogLevel.All)) +) + +pipe( + program, + Effect.provide(SqlLive), + Effect.tapErrorCause(Effect.logError), + Effect.runFork +) diff --git a/packages/sql-mssql/examples/migrations/0001_create_people.ts b/packages/sql-mssql/examples/migrations/0001_create_people.ts new file mode 100644 index 0000000000..1b1c5fe7f0 --- /dev/null +++ b/packages/sql-mssql/examples/migrations/0001_create_people.ts @@ -0,0 +1,12 @@ +import * as Sql from "@effect/sql-mssql" +import { Effect } from "effect" + +export default Effect.flatMap( + Sql.client.MssqlClient, + (sql) => + sql`CREATE TABLE people ( + id INT IDENTITY(1,1) PRIMARY KEY, + name NVARCHAR(255) NOT NULL, + created_at DATETIME NOT NULL DEFAULT GETDATE() + )` +) diff --git a/packages/sql-mssql/package.json b/packages/sql-mssql/package.json new file mode 100644 index 0000000000..963e090585 --- /dev/null +++ b/packages/sql-mssql/package.json @@ -0,0 +1,53 @@ +{ + "name": "@effect/sql-mssql", + "version": "0.0.0", + "type": "module", + "license": "MIT", + "description": "A Microsoft SQL Server toolkit for Effect", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/effect-ts/effect.git", + "directory": "packages/sql-mssql" + }, + "bugs": { + "url": "https://github.com/effect-ts/effect/issues" + }, + "tags": [ + "typescript", + "sql", + "database" + ], + "keywords": [ + "typescript", + "sql", + "database" + ], + "publishConfig": { + "access": "public", + "directory": "dist", + "provenance": true + }, + "scripts": { + "build": "pnpm build-esm && pnpm build-cjs && pnpm build-annotate && build-utils pack-v2", + "build-esm": "tsc -b tsconfig.build.json", + "build-cjs": "babel build/esm --plugins @babel/transform-export-namespace-from --plugins @babel/transform-modules-commonjs --out-dir build/cjs --source-maps", + "build-annotate": "babel build --plugins annotate-pure-calls --out-dir build --source-maps", + "check": "tsc -b tsconfig.json", + "test": "vitest", + "coverage": "vitest --coverage" + }, + "devDependencies": { + "@effect/platform": "workspace:^", + "@effect/sql": "workspace:^", + "effect": "workspace:^" + }, + "peerDependencies": { + "@effect/platform": "workspace:^", + "@effect/sql": "workspace:^", + "effect": "workspace:^" + }, + "dependencies": { + "tedious": "^18" + } +} diff --git a/packages/sql-mssql/src/Client.ts b/packages/sql-mssql/src/Client.ts new file mode 100644 index 0000000000..2956c9b4ff --- /dev/null +++ b/packages/sql-mssql/src/Client.ts @@ -0,0 +1,482 @@ +/** + * @since 1.0.0 + */ +import * as Client from "@effect/sql/Client" +import type { Connection } from "@effect/sql/Connection" +import { SqlError } from "@effect/sql/Error" +import * as Statement from "@effect/sql/Statement" +import * as Config from "effect/Config" +import type { ConfigError } from "effect/ConfigError" +import * as Context from "effect/Context" +import * as Duration from "effect/Duration" +import * as Effect from "effect/Effect" +import * as Exit from "effect/Exit" +import { identity, pipe } from "effect/Function" +import * as Layer from "effect/Layer" +import * as Option from "effect/Option" +import * as Pool from "effect/Pool" +import * as Scope from "effect/Scope" +import * as Secret from "effect/Secret" +import * as Tedious from "tedious" +import type { ConnectionOptions } from "tedious/lib/connection.js" +import type { DataType } from "tedious/lib/data-type.js" +import type { ParameterOptions } from "tedious/lib/request.js" +import type { Parameter } from "./Parameter.js" +import type * as Procedure from "./Procedure.js" + +/** + * @category models + * @since 1.0.0 + */ +export interface MssqlClient extends Client.Client { + readonly config: MssqlClientConfig + + readonly param: ( + type: DataType, + value: Statement.Primitive, + options?: ParameterOptions + ) => Statement.Fragment + + readonly call: < + I extends Record>, + O extends Record>, + A extends object + >( + procedure: Procedure.ProcedureWithValues + ) => Effect.Effect, SqlError> +} + +/** + * @category tags + * @since 1.0.0 + */ +export const MssqlClient = Context.GenericTag("@effect/sql-mssql/MssqlClient") + +/** + * @category models + * @since 1.0.0 + */ +export interface MssqlClientConfig { + readonly domain?: string | undefined + readonly server: string + readonly instanceName?: string | undefined + readonly encrypt?: boolean | undefined + readonly trustServer?: boolean | undefined + readonly port?: number | undefined + readonly authType?: string | undefined + readonly database?: string | undefined + readonly username?: string | undefined + readonly password?: Secret.Secret | undefined + readonly connectTimeout?: Duration.DurationInput | undefined + + readonly minConnections?: number | undefined + readonly maxConnections?: number | undefined + readonly connectionTTL?: Duration.DurationInput | undefined + + readonly parameterTypes?: Record | undefined + + readonly transformResultNames?: ((str: string) => string) | undefined + readonly transformQueryNames?: ((str: string) => string) | undefined +} + +interface MssqlConnection extends Connection { + readonly call: ( + procedure: Procedure.ProcedureWithValues + ) => Effect.Effect + + readonly begin: Effect.Effect + readonly commit: Effect.Effect + readonly savepoint: (name: string) => Effect.Effect + readonly rollback: (name?: string) => Effect.Effect +} + +const TransactionConnection = Client.TransactionConnection as unknown as Context.Tag< + readonly [conn: MssqlConnection, counter: number], + readonly [conn: MssqlConnection, counter: number] +> + +/** + * @category constructors + * @since 1.0.0 + */ +export const make = ( + options: MssqlClientConfig +): Effect.Effect => + Effect.gen(function*(_) { + const parameterTypes = options.parameterTypes ?? defaultParameterTypes + const compiler = makeCompiler(options.transformQueryNames) + + const transformRows = Client.defaultTransforms( + options.transformResultNames! + ).array + + // eslint-disable-next-line prefer-const + let pool: Pool.Pool + + const makeConnection = Effect.gen(function*(_) { + const conn = new Tedious.Connection({ + options: { + port: options.port, + database: options.database, + trustServerCertificate: options.trustServer ?? true, + connectTimeout: options.connectTimeout + ? Duration.toMillis(Duration.decode(options.connectTimeout)) + : undefined, + rowCollectionOnRequestCompletion: true, + useColumnNames: false, + instanceName: options.instanceName, + encrypt: options.encrypt ?? false + } as ConnectionOptions, + server: options.server, + authentication: { + type: (options.authType as any) ?? "default", + options: { + userName: options.username, + password: options.password + ? Secret.value(options.password) + : undefined + } + } + }) + + yield* _(Effect.addFinalizer(() => Effect.sync(() => conn.close()))) + + yield* _( + Effect.async((resume) => { + conn.connect((error) => { + if (error) { + resume(Effect.fail(new SqlError({ error }))) + } else { + resume(Effect.unit) + } + }) + }) + ) + + const run = ( + sql: string, + values?: ReadonlyArray, + transform = true, + rowsAsArray = false + ) => + Effect.async((resume) => { + const req = new Tedious.Request(sql, (error, _rowCount, result) => { + if (error) { + resume(Effect.fail(new SqlError({ error }))) + return + } + + if (rowsAsArray) { + result = result.map((row: any) => row.map((_: any) => _.value)) + } else { + result = rowsToObjects(result) + + if (transform && options.transformResultNames) { + result = transformRows(result) as any + } + } + + resume(Effect.succeed(result)) + }) + + if (values) { + for (let i = 0, len = values.length; i < len; i++) { + const value = values[i] + const name = numberToAlpha(i) + + if (isMssqlParam(value)) { + req.addParameter(name, value.i0, value.i1, value.i2) + } else { + const kind = Statement.primitiveKind(value) + const type = parameterTypes[kind] + req.addParameter(name, type, value) + } + } + } + + conn.cancel() + conn.execSql(req) + }) + + const runProcedure = (procedure: Procedure.ProcedureWithValues) => + Effect.async((resume) => { + const result: Record = {} + + const req = new Tedious.Request( + escape(procedure.name), + (error, _, rows) => { + if (error) { + resume(Effect.fail(new SqlError({ error }))) + } else { + rows = rowsToObjects(rows) + if (options.transformResultNames) { + rows = transformRows(rows) as any + } + resume( + Effect.succeed({ + params: result, + rows + }) + ) + } + } + ) + + for (const name in procedure.params) { + const param = procedure.params[name] + const value = procedure.values[name] + req.addParameter(name, param.type, value, param.options) + } + + for (const name in procedure.outputParams) { + const param = procedure.outputParams[name] + req.addOutputParameter(name, param.type, undefined, param.options) + } + + req.on("returnValue", (name, value) => { + result[name] = value + }) + + conn.cancel() + conn.callProcedure(req) + }) + + const connection = identity({ + execute(sql, params) { + return run(sql, params) + }, + executeWithoutTransform(sql, params) { + return run(sql, params, false) + }, + executeValues(sql, params) { + return run(sql, params, true, true) + }, + executeRaw(sql, params) { + return run(sql, params) + }, + executeStream() { + return Effect.dieMessage("executeStream not implemented") + }, + call: (procedure) => { + return runProcedure(procedure) + }, + begin: Effect.async((resume) => { + conn.beginTransaction((error) => { + if (error) { + resume(Effect.fail(new SqlError({ error }))) + } else { + resume(Effect.unit) + } + }) + }), + commit: Effect.async((resume) => { + conn.commitTransaction((error) => { + if (error) { + resume(Effect.fail(new SqlError({ error }))) + } else { + resume(Effect.unit) + } + }) + }), + savepoint: (name: string) => + Effect.async((resume) => { + conn.saveTransaction((error) => { + if (error) { + resume(Effect.fail(new SqlError({ error }))) + } else { + resume(Effect.unit) + } + }, name) + }), + rollback: (name?: string) => + Effect.async((resume) => { + conn.rollbackTransaction((error) => { + if (error) { + resume(Effect.fail(new SqlError({ error }))) + } else { + resume(Effect.unit) + } + }, name) + }) + }) + + yield* _( + Effect.async((resume) => { + conn.on("error", (_) => resume(Effect.fail(_))) + }), + Effect.catchAll(() => Pool.invalidate(pool, connection)), + Effect.interruptible, + Effect.forkScoped + ) + + return connection + }) + + pool = yield* _( + Pool.makeWithTTL({ + acquire: makeConnection, + min: options.minConnections ?? 1, + max: options.maxConnections ?? 10, + timeToLive: options.connectionTTL ?? Duration.minutes(45) + }) + ) + + const makeRootTx: Effect.Effect< + readonly [Scope.CloseableScope | undefined, MssqlConnection, number], + SqlError + > = Effect.flatMap( + Scope.make(), + (scope) => Effect.map(Scope.extend(Pool.get(pool), scope), (conn) => [scope, conn, 0] as const) + ) + + const withTransaction = ( + effect: Effect.Effect + ): Effect.Effect => + Effect.acquireUseRelease( + pipe( + Effect.serviceOption(TransactionConnection), + Effect.flatMap( + Option.match({ + onNone: () => makeRootTx, + onSome: ([conn, count]) => Effect.succeed([undefined, conn, count + 1] as const) + }) + ), + Effect.tap(([, conn, id]) => + id > 0 + ? conn.savepoint(`effect_sql_${id}`) + : conn.begin + ) + ), + ([, conn, id]) => Effect.provideService(effect, TransactionConnection, [conn, id]), + ([scope, conn, id], exit) => { + const effect = Exit.isSuccess(exit) + ? id > 0 + ? Effect.unit + : Effect.orDie(conn.commit) + : Effect.orDie(conn.rollback(id > 0 ? `effect_sql_${id}` : undefined)) + return scope !== undefined ? Effect.ensuring(effect, Scope.close(scope, exit)) : effect + } + ) + + return identity(Object.assign( + Client.make({ + acquirer: pool.get, + compiler, + transactionAcquirer: pool.get + }), + { + config: options, + + withTransaction, + + param: ( + type: DataType, + value: Statement.Primitive, + options: ParameterOptions = {} + ) => mssqlParam(type, value, options), + + call: < + I extends Record>, + O extends Record>, + A + >( + procedure: Procedure.ProcedureWithValues + ) => Effect.scoped(Effect.flatMap(pool.get, (_) => _.call(procedure))) + } + )) + }) + +/** + * @category layers + * @since 1.0.0 + */ +export const layer: ( + config: Config.Config.Wrap +) => Layer.Layer = ( + config: Config.Config.Wrap +) => Layer.scoped(MssqlClient, Effect.flatMap(Config.unwrap(config), make)) + +/** + * @category compiler + * @since 1.0.0 + */ +export const makeCompiler = (transform?: (_: string) => string) => + Statement.makeCompiler({ + placeholder: (_) => `@${numberToAlpha(_ - 1)}`, + onIdentifier: transform ? (_) => escape(transform(_)) : escape, + onRecordUpdate: (placeholders, valueAlias, valueColumns, values) => [ + `(values ${placeholders}) AS ${valueAlias}${valueColumns}`, + values.flat() + ], + onCustom: (type, placeholder) => { + switch (type.kind) { + case "MssqlParam": { + return [placeholder(), [type] as any] + } + } + }, + onInsert: (columns, placeholders, values) => [ + `(${columns.join(",")}) OUTPUT INSERTED.* VALUES ${placeholders}`, + values.flat() + ] + }) + +/** + * @since 1.0.0 + */ +export const defaultParameterTypes: Record = { + string: Tedious.TYPES.VarChar, + number: Tedious.TYPES.Int, + bigint: Tedious.TYPES.BigInt, + boolean: Tedious.TYPES.Bit, + Date: Tedious.TYPES.DateTime, + Uint8Array: Tedious.TYPES.VarBinary, + Int8Array: Tedious.TYPES.VarBinary, + null: Tedious.TYPES.Bit +} + +// compiler helpers + +const escape = (str: string) => "[" + str.replace(/\]/g, "]]").replace(/\./g, "].[") + "]" + +const charCodeA = "a".charCodeAt(0) +function numberToAlpha(n: number) { + let s = "" + while (n >= 0) { + s = String.fromCharCode((n % 26) + charCodeA) + s + n = Math.floor(n / 26) - 1 + } + return s +} + +function rowsToObjects(rows: ReadonlyArray) { + const newRows = new Array(rows.length) + + for (let i = 0, len = rows.length; i < len; i++) { + const row = rows[i] + const newRow: any = {} + for (let j = 0, columnLen = row.length; j < columnLen; j++) { + const column = row[j] + newRow[column.metadata.colName] = column.value + } + newRows[i] = newRow + } + + return newRows +} + +// custom types + +type MssqlCustom = MssqlParam + +interface MssqlParam extends + Statement.Custom< + "MssqlParam", + DataType, + Statement.Primitive, + ParameterOptions + > +{} + +const mssqlParam = Statement.custom("MssqlParam") +const isMssqlParam = Statement.isCustom("MssqlParam") diff --git a/packages/sql-mssql/src/Migrator.ts b/packages/sql-mssql/src/Migrator.ts new file mode 100644 index 0000000000..00e2bb6f99 --- /dev/null +++ b/packages/sql-mssql/src/Migrator.ts @@ -0,0 +1,46 @@ +/** + * @since 1.0.0 + */ +import type { SqlError } from "@effect/sql/Error" +import * as Migrator from "@effect/sql/Migrator" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import * as Client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * from "@effect/sql/Migrator" + +/** + * @category constructor + * @since 1.0.0 + */ +export const run: ( + options: Migrator.MigratorOptions +) => Effect.Effect< + ReadonlyArray, + SqlError | Migrator.MigrationError, + Client.MssqlClient | R +> = Migrator.make({ + getClient: Client.MssqlClient, + ensureTable(sql, table) { + return sql`IF OBJECT_ID(N'${sql.literal(table)}', N'U') IS NULL + CREATE TABLE ${sql(table)} ( + migration_id INT NOT NULL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + created_at DATETIME NOT NULL DEFAULT GETDATE() + )` + }, + dumpSchema(_sql, _path, _table) { + return Effect.unit + } +}) + +/** + * @category layers + * @since 1.0.0 + */ +export const layer = ( + options: Migrator.MigratorOptions +): Layer.Layer => Layer.effectDiscard(run(options)) diff --git a/packages/sql-mssql/src/Parameter.ts b/packages/sql-mssql/src/Parameter.ts new file mode 100644 index 0000000000..93537436ae --- /dev/null +++ b/packages/sql-mssql/src/Parameter.ts @@ -0,0 +1,46 @@ +/** + * @since 1.0.0 + */ +import { identity } from "effect/Function" +import type { DataType } from "tedious/lib/data-type.js" +import type { ParameterOptions } from "tedious/lib/request.js" + +/** + * @category type id + * @since 1.0.0 + */ +export const ParameterId = Symbol.for("@sqlfx/mssql/Parameter") + +/** + * @category type id + * @since 1.0.0 + */ +export type ParameterId = typeof ParameterId + +/** + * @category model + * @since 1.0.0 + */ +export interface Parameter { + readonly [ParameterId]: (_: never) => A + readonly _tag: "Parameter" + readonly name: string + readonly type: DataType + readonly options: ParameterOptions +} + +/** + * @category constructor + * @since 1.0.0 + */ +export const make = ( + name: string, + type: DataType, + options: ParameterOptions = {} +): Parameter => ({ + [ParameterId]: identity, + _tag: "Parameter", + name, + type, + options +}) diff --git a/packages/sql-mssql/src/Procedure.ts b/packages/sql-mssql/src/Procedure.ts new file mode 100644 index 0000000000..3e24a8f478 --- /dev/null +++ b/packages/sql-mssql/src/Procedure.ts @@ -0,0 +1,180 @@ +/** + * @since 1.0.0 + */ +import type { Row } from "@effect/sql/Connection" +import { identity } from "effect/Function" +import type { Pipeable } from "effect/Pipeable" +import { pipeArguments } from "effect/Pipeable" +import type { Covariant } from "effect/Types" +import type { DataType } from "tedious/lib/data-type.js" +import type { ParameterOptions } from "tedious/lib/request.js" +import * as Parameter from "./Parameter.js" + +/** + * @category type id + * @since 1.0.0 + */ +export const TypeId = Symbol.for("@effect/sql-mssql/Procedure") + +/** + * @category type id + * @since 1.0.0 + */ +export type TypeId = typeof TypeId + +/** + * @category model + * @since 1.0.0 + */ +export interface Procedure< + I extends Record>, + O extends Record>, + A = never +> extends Pipeable { + readonly [TypeId]: { + readonly _A: Covariant + } + readonly _tag: "Procedure" + readonly name: string + readonly params: I + readonly outputParams: O +} + +/** + * @category model + * @since 1.0.0 + */ +export interface ProcedureWithValues< + I extends Record>, + O extends Record>, + A +> extends Procedure { + readonly values: Procedure.ParametersRecord +} + +/** + * @since 1.0.0 + */ +export namespace Procedure { + /** + * @since 1.0.0 + */ + export type ParametersRecord< + A extends Record> + > = + & { + readonly [K in keyof A]: A[K] extends Parameter.Parameter ? T + : never + } + & {} + + /** + * @category model + * @since 1.0.0 + */ + export interface Result< + O extends Record>, + A + > { + readonly output: ParametersRecord + readonly rows: ReadonlyArray + } +} + +type Simplify = { [K in keyof A]: A[K] } & {} + +const procedureProto = { + [TypeId]: { + _A: identity + }, + _tag: "Procedure", + pipe() { + return pipeArguments(this, arguments) + } +} + +/** + * @category constructor + * @since 1.0.0 + */ +export const make = (name: string): Procedure<{}, {}> => { + const procedure = Object.create(procedureProto) + procedure.name = name + procedure.params = {} + procedure.outputParams = {} + return procedure +} + +/** + * @category combinator + * @since 1.0.0 + */ +export const param = () => +( + name: N, + type: T, + options?: ParameterOptions +) => +< + I extends Record>, + O extends Record> +>( + self: Procedure +): Procedure }>, O> => ({ + ...self, + params: { + ...self.params, + [name]: Parameter.make(name, type, options) + } +}) + +/** + * @category combinator + * @since 1.0.0 + */ +export const outputParam = () => +( + name: N, + type: T, + options?: ParameterOptions +) => +< + I extends Record>, + O extends Record> +>( + self: Procedure +): Procedure }>> => ({ + ...self, + outputParams: { + ...self.outputParams, + [name]: Parameter.make(name, type, options) + } +}) + +/** + * @category combinator + * @since 1.0.0 + */ +export const withRows = () => +< + I extends Record>, + O extends Record> +>( + self: Procedure +): Procedure => self as any + +/** + * @category combinator + * @since 1.0.0 + */ +export const compile = < + I extends Record>, + O extends Record>, + A +>( + self: Procedure +) => +(input: Procedure.ParametersRecord): ProcedureWithValues => ({ + ...self, + values: input +}) diff --git a/packages/sql-mssql/src/index.ts b/packages/sql-mssql/src/index.ts new file mode 100644 index 0000000000..93beeb0f9c --- /dev/null +++ b/packages/sql-mssql/src/index.ts @@ -0,0 +1,50 @@ +/** + * @since 1.0.0 + */ + +/** + * @since 1.0.0 + */ +export * as client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * as error from "@effect/sql/Error" + +/** + * @since 1.0.0 + */ +export * as migrator from "./Migrator.js" + +/** + * @since 1.0.0 + */ +export * as parameter from "./Parameter.js" + +/** + * @since 1.0.0 + */ +export * as procedure from "./Procedure.js" + +/** + * @since 1.0.0 + */ +export * as resolver from "@effect/sql/Resolver" + +/** + * @since 1.0.0 + */ +export * as schema from "@effect/sql/Schema" + +/** + * @since 1.0.0 + */ +export * as statement from "@effect/sql/Statement" + +export { + /** + * @since 1.0.0 + */ + TYPES as types +} from "tedious" diff --git a/packages/sql-mssql/test/Client.test.ts b/packages/sql-mssql/test/Client.test.ts new file mode 100644 index 0000000000..1d43227685 --- /dev/null +++ b/packages/sql-mssql/test/Client.test.ts @@ -0,0 +1,76 @@ +import * as Sql from "@effect/sql-mssql" +import { Effect } from "effect" +import { describe, expect, it } from "vitest" + +const sql = Effect.runSync( + Effect.scoped( + Sql.client.make({ + server: "" + }) + ) +) +const compiler = Sql.client.makeCompiler() + +describe("mssql", () => { + it("insert helper", () => { + const [query, params] = compiler.compile( + sql`INSERT INTO ${sql("people")} ${sql.insert({ name: "Tim", age: 10 })}` + ) + expect(query).toEqual( + `INSERT INTO [people] ([name],[age]) OUTPUT INSERTED.* VALUES (@a,@b)` + ) + expect(params).toEqual(["Tim", 10]) + }) + + it("update helper", () => { + const [query, params] = compiler.compile( + sql`UPDATE people SET name = data.name FROM ${ + sql.updateValues( + [{ name: "Tim" }, { name: "John" }], + "data" + ) + }` + ) + expect(query).toEqual( + `UPDATE people SET name = data.name FROM (values (@a),(@b)) AS data([name])` + ) + expect(params).toEqual(["Tim", "John"]) + }) + + it("array helper", () => { + const [query, params] = compiler.compile( + sql`SELECT * FROM ${sql("people")} WHERE id IN ${sql.in([1, 2, "string"])}` + ) + expect(query).toEqual(`SELECT * FROM [people] WHERE id IN (@a,@b,@c)`) + expect(params).toEqual([1, 2, "string"]) + }) + + it("param types", () => { + const [query, params] = compiler.compile( + sql`SELECT * FROM ${sql("people")} WHERE id = ${ + sql.param( + Sql.types.BigInt, + 1 + ) + }` + ) + expect(query).toEqual(`SELECT * FROM [people] WHERE id = @a`) + expect(Sql.statement.isCustom("MssqlParam")(params[0])).toEqual(true) + const param = params[0] as unknown as Sql.statement.Custom< + "MsSqlParam", + any, + any, + any + > + expect(param.i0).toEqual(Sql.types.BigInt) + expect(param.i1).toEqual(1) + expect(param.i2).toEqual({}) + }) + + it("escape [", () => { + const [query] = compiler.compile( + sql`SELECT * FROM ${sql("peo[]ple.te[st]ing")}` + ) + expect(query).toEqual(`SELECT * FROM [peo[]]ple].[te[st]]ing]`) + }) +}) diff --git a/packages/sql-mssql/tsconfig.build.json b/packages/sql-mssql/tsconfig.build.json new file mode 100644 index 0000000000..808406fd4c --- /dev/null +++ b/packages/sql-mssql/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.src.json", + "references": [{ "path": "../effect" }, { "path": "../sql" }], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/build.tsbuildinfo", + "outDir": "build/esm", + "declarationDir": "build/dts", + "stripInternal": true + } +} diff --git a/packages/sql-mssql/tsconfig.examples.json b/packages/sql-mssql/tsconfig.examples.json new file mode 100644 index 0000000000..119ff192eb --- /dev/null +++ b/packages/sql-mssql/tsconfig.examples.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["examples"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../experimental" }, + { "path": "../sql" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/examples.tsbuildinfo", + "rootDir": "examples", + "noEmit": true + } +} diff --git a/packages/sql-mssql/tsconfig.json b/packages/sql-mssql/tsconfig.json new file mode 100644 index 0000000000..3edbf6b8a5 --- /dev/null +++ b/packages/sql-mssql/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "include": [], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "tsconfig.test.json" }, + { "path": "tsconfig.examples.json" } + ] +} diff --git a/packages/sql-mssql/tsconfig.src.json b/packages/sql-mssql/tsconfig.src.json new file mode 100644 index 0000000000..424a843861 --- /dev/null +++ b/packages/sql-mssql/tsconfig.src.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src"], + "references": [{ "path": "../effect" }, { "path": "../sql" }], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/src.tsbuildinfo", + "rootDir": "src", + "outDir": "build/src" + } +} diff --git a/packages/sql-mssql/tsconfig.test.json b/packages/sql-mssql/tsconfig.test.json new file mode 100644 index 0000000000..497f697f10 --- /dev/null +++ b/packages/sql-mssql/tsconfig.test.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["test"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../sql" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/test.tsbuildinfo", + "rootDir": "test", + "noEmit": true + } +} diff --git a/packages/sql-mssql/vitest.config.ts b/packages/sql-mssql/vitest.config.ts new file mode 100644 index 0000000000..0411095f25 --- /dev/null +++ b/packages/sql-mssql/vitest.config.ts @@ -0,0 +1,6 @@ +import { mergeConfig, type UserConfigExport } from "vitest/config" +import shared from "../../vitest.shared.js" + +const config: UserConfigExport = {} + +export default mergeConfig(shared, config) diff --git a/packages/sql-mysql2/LICENSE b/packages/sql-mysql2/LICENSE new file mode 100644 index 0000000000..7f6fe480f7 --- /dev/null +++ b/packages/sql-mysql2/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023-present The Contributors + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/packages/sql-mysql2/README.md b/packages/sql-mysql2/README.md new file mode 100644 index 0000000000..c76aa86803 --- /dev/null +++ b/packages/sql-mysql2/README.md @@ -0,0 +1,5 @@ +# Effect SQL - MySQL + +An @effect/sql implementation using the `mysql2` library. + +See here for more information: https://github.com/Effect-TS/effect/tree/main/packages/sql diff --git a/packages/sql-mysql2/docgen.json b/packages/sql-mysql2/docgen.json new file mode 100644 index 0000000000..f980a32f52 --- /dev/null +++ b/packages/sql-mysql2/docgen.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../node_modules/@effect/docgen/schema.json", + "exclude": [ + "src/internal/**/*.ts" + ] +} diff --git a/packages/sql-mysql2/examples/statement-transform.ts b/packages/sql-mysql2/examples/statement-transform.ts new file mode 100644 index 0000000000..b3e328f092 --- /dev/null +++ b/packages/sql-mysql2/examples/statement-transform.ts @@ -0,0 +1,45 @@ +import * as DevTools from "@effect/experimental/DevTools" +import * as Sql from "@effect/sql-mysql2" +import { Config, Effect, FiberRef, FiberRefs, Layer, Option, Secret, String } from "effect" + +const currentResourceName = FiberRef.unsafeMake("") + +const SqlTracingLive = Sql.statement.setTransformer((prev, sql, refs, span) => { + const [query, params] = prev.compile() + return sql.unsafe( + `/* ${ + JSON.stringify({ + trace_id: span.traceId, + span_id: span.spanId, + resource_name: Option.getOrUndefined(FiberRefs.get(refs, currentResourceName)) + }) + } */ ${query}`, + params + ) +}) + +const EnvLive = Sql.client.layer({ + database: Config.succeed("effect_dev"), + username: Config.succeed("effect"), + password: Config.succeed(Secret.fromString("password")), + transformQueryNames: Config.succeed(String.camelToSnake), + transformResultNames: Config.succeed(String.snakeToCamel) +}).pipe( + Layer.provide(SqlTracingLive), + Layer.provide(DevTools.layer()) +) + +const program = Effect.gen(function*(_) { + const sql = yield* _(Sql.client.MysqlClient) + yield* _( + sql`SELECT * FROM people`, + Effect.replicateEffect(50), + Effect.locally(currentResourceName, "GET /people") + ) +}) + +program.pipe( + Effect.provide(EnvLive), + Effect.tapErrorCause(Effect.logError), + Effect.runFork +) diff --git a/packages/sql-mysql2/package.json b/packages/sql-mysql2/package.json new file mode 100644 index 0000000000..70c1509ed3 --- /dev/null +++ b/packages/sql-mysql2/package.json @@ -0,0 +1,53 @@ +{ + "name": "@effect/sql-mysql2", + "version": "0.0.0", + "type": "module", + "license": "MIT", + "description": "A MySQL toolkit for Effect", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/effect-ts/effect.git", + "directory": "packages/sql-mysql2" + }, + "bugs": { + "url": "https://github.com/effect-ts/effect/issues" + }, + "tags": [ + "typescript", + "sql", + "database" + ], + "keywords": [ + "typescript", + "sql", + "database" + ], + "publishConfig": { + "access": "public", + "directory": "dist", + "provenance": true + }, + "scripts": { + "build": "pnpm build-esm && pnpm build-cjs && pnpm build-annotate && build-utils pack-v2", + "build-esm": "tsc -b tsconfig.build.json", + "build-cjs": "babel build/esm --plugins @babel/transform-export-namespace-from --plugins @babel/transform-modules-commonjs --out-dir build/cjs --source-maps", + "build-annotate": "babel build --plugins annotate-pure-calls --out-dir build --source-maps", + "check": "tsc -b tsconfig.json", + "test": "vitest", + "coverage": "vitest --coverage" + }, + "devDependencies": { + "@effect/platform": "workspace:^", + "@effect/sql": "workspace:^", + "effect": "workspace:^" + }, + "peerDependencies": { + "@effect/platform": "workspace:^", + "@effect/sql": "workspace:^", + "effect": "workspace:^" + }, + "dependencies": { + "mysql2": "^3" + } +} diff --git a/packages/sql-mysql2/src/Client.ts b/packages/sql-mysql2/src/Client.ts new file mode 100644 index 0000000000..ea956370dd --- /dev/null +++ b/packages/sql-mysql2/src/Client.ts @@ -0,0 +1,230 @@ +/** + * @since 1.0.0 + */ +import * as Client from "@effect/sql/Client" +import type { Connection } from "@effect/sql/Connection" +import { SqlError } from "@effect/sql/Error" +import * as Statement from "@effect/sql/Statement" +import { asyncPauseResume } from "@effect/sql/Stream" +import * as Chunk from "effect/Chunk" +import * as Config from "effect/Config" +import type { ConfigError } from "effect/ConfigError" +import * as Context from "effect/Context" +import * as Duration from "effect/Duration" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import type { Scope } from "effect/Scope" +import * as Secret from "effect/Secret" +import * as Stream from "effect/Stream" +import * as Mysql from "mysql2" + +/** + * @category models + * @since 1.0.0 + */ +export interface MysqlClient extends Client.Client { + readonly config: MysqlClientConfig +} + +/** + * @category tags + * @since 1.0.0 + */ +export const MysqlClient = Context.GenericTag("sqlfx/mysql2/MysqlClient") + +/** + * @category models + * @since 1.0.0 + */ +export interface MysqlClientConfig { + /** + * Connection URI. Setting this will override the other connection options + */ + readonly url?: Secret.Secret + + readonly host?: string + readonly port?: number + readonly database?: string + readonly username?: string + readonly password?: Secret.Secret + + readonly maxConnections?: number + readonly connectionTTL?: Duration.DurationInput + + readonly poolConfig?: Mysql.PoolOptions + + readonly transformResultNames?: (str: string) => string + readonly transformQueryNames?: (str: string) => string +} + +const escape = Statement.defaultEscape("`") + +/** + * @category constructors + * @since 1.0.0 + */ +export const make = ( + options: MysqlClientConfig +): Effect.Effect => + Effect.gen(function*(_) { + const compiler = makeCompiler(options.transformQueryNames) + + const transformRows = Client.defaultTransforms( + options.transformResultNames! + ).array + + class ConnectionImpl implements Connection { + constructor(private readonly conn: Mysql.PoolConnection | Mysql.Pool) {} + + private run( + sql: string, + values?: ReadonlyArray, + transform = true, + rowsAsArray = false, + method: "execute" | "query" = "execute" + ) { + return Effect.async, SqlError>((resume) => { + this.conn[method]({ + sql, + values, + rowsAsArray + }, (error: unknown | null, results: ReadonlyArray, _fields: any) => { + if (error) { + resume(Effect.fail(new SqlError({ error }))) + } else if (transform && !rowsAsArray && options.transformResultNames) { + resume(Effect.succeed(transformRows(results))) + } else { + resume(Effect.succeed(results)) + } + }) + }) + } + + execute(sql: string, params: ReadonlyArray) { + return this.run(sql, params) + } + executeWithoutTransform(sql: string, params: ReadonlyArray) { + return this.run(sql, params, false) + } + executeValues(sql: string, params: ReadonlyArray) { + return this.run(sql, params, true, true) + } + executeRaw(sql: string, params?: ReadonlyArray) { + return this.run(sql, params, true, false, "query") + } + executeStream(sql: string, params: ReadonlyArray) { + const stream = queryStream(this.conn as any, sql, params) + return options.transformResultNames + ? Stream.mapChunks(stream, (_) => + Chunk.unsafeFromArray( + transformRows(Chunk.toReadonlyArray(_) as Array) + )) + : stream + } + } + + const pool = options.url + ? Mysql.createPool(Secret.value(options.url)) + : Mysql.createPool({ + ...(options.poolConfig ?? {}), + host: options.host, + port: options.port, + database: options.database, + user: options.username, + password: options.password + ? Secret.value(options.password) + : undefined, + connectionLimit: options.maxConnections, + idleTimeout: options.connectionTTL + ? Duration.toMillis(options.connectionTTL) + : undefined + } as Mysql.PoolOptions) + + yield* _(Effect.addFinalizer(() => + Effect.async((resume) => { + pool.end(() => resume(Effect.unit)) + }) + )) + + const poolConnection = new ConnectionImpl(pool) + + const acquireConn = Effect.acquireRelease( + Effect.async((resume) => { + pool.getConnection((error, conn) => { + if (error) { + resume(new SqlError({ error })) + } else { + resume(Effect.succeed(conn)) + } + }) + }), + (conn) => Effect.sync(() => conn.release()) + ) + + const transactionAcquirer = Effect.map( + acquireConn, + (conn) => new ConnectionImpl(conn) + ) + + return Object.assign( + Client.make({ + acquirer: Effect.succeed(poolConnection), + transactionAcquirer, + compiler + }), + { config: options } + ) + }) + +/** + * @category layers + * @since 1.0.0 + */ +export const layer: ( + config: Config.Config.Wrap +) => Layer.Layer = ( + config: Config.Config.Wrap +) => Layer.scoped(MysqlClient, Effect.flatMap(Config.unwrap(config), make)) + +/** + * @category compiler + * @since 1.0.0 + */ +export const makeCompiler = (transform?: (_: string) => string) => + Statement.makeCompiler({ + placeholder: (_) => `?`, + onIdentifier: transform ? (_) => escape(transform(_)) : escape, + onCustom: () => ["", []], + onRecordUpdate: () => ["", []] + }) + +function queryStream( + conn: Mysql.PoolConnection, + sql: string, + params?: ReadonlyArray +) { + return asyncPauseResume((emit) => { + const query = conn.query(sql, params).stream() + let buffer: Array = [] + let taskPending = false + query.on("error", (error: unknown) => emit.fail(new SqlError({ error }))) + query.on("data", (row: any) => { + buffer.push(row) + if (!taskPending) { + taskPending = true + queueMicrotask(() => { + const items = buffer + buffer = [] + emit.array(items) + taskPending = false + }) + } + }) + query.on("end", () => emit.end()) + return { + onInterrupt: Effect.sync(() => query.destroy()), + onPause: Effect.sync(() => query.pause()), + onResume: Effect.sync(() => query.resume()) + } + }) +} diff --git a/packages/sql-mysql2/src/Migrator.ts b/packages/sql-mysql2/src/Migrator.ts new file mode 100644 index 0000000000..500f0dcb37 --- /dev/null +++ b/packages/sql-mysql2/src/Migrator.ts @@ -0,0 +1,107 @@ +/** + * @since 1.0.0 + */ +import * as Command from "@effect/platform/Command" +import type { CommandExecutor } from "@effect/platform/CommandExecutor" +import { FileSystem } from "@effect/platform/FileSystem" +import { Path } from "@effect/platform/Path" +import type { SqlError } from "@effect/sql/Error" +import * as Migrator from "@effect/sql/Migrator" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import * as Secret from "effect/Secret" +import * as Client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * from "@effect/sql/Migrator" + +/** + * @category constructor + * @since 1.0.0 + */ +export const run: ( + options: Migrator.MigratorOptions +) => Effect.Effect< + ReadonlyArray, + SqlError | Migrator.MigrationError, + Client.MysqlClient | R | FileSystem | Path | CommandExecutor +> = Migrator.make({ + getClient: Client.MysqlClient, + ensureTable(sql, table) { + return sql`CREATE TABLE IF NOT EXISTS ${sql(table)} ( + migration_id INTEGER UNSIGNED NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + name VARCHAR(255) NOT NULL, + PRIMARY KEY (migration_id) + )` + }, + lockTable(sql, table) { + return sql`LOCK TABLE ${sql(table)} IN ACCESS EXCLUSIVE MODE` + }, + dumpSchema(sql, path, table) { + const mysqlDump = (args: Array) => + Effect.gen(function*(_) { + const dump = yield* _( + Command.make( + "mysqldump", + ...(sql.config.username ? ["-u", sql.config.username] : []), + ...(sql.config.database ? [sql.config.database] : []), + "--skip-comments", + "--compact", + ...args + ), + Command.env({ + PATH: (globalThis as any).process?.env.PATH, + MYSQL_HOST: sql.config.host, + MYSQL_TCP_PORT: sql.config.port?.toString(), + MYSQL_PWD: sql.config.password + ? Secret.value(sql.config.password) + : undefined + }), + Command.string + ) + + return dump.replace(/^\/\*.*$/gm, "") + .replace(/\n{2,}/gm, "\n\n") + .trim() + }).pipe( + Effect.mapError((error) => new Migrator.MigrationError({ reason: "failed", message: error.message })) + ) + + const dumpSchema = mysqlDump(["--no-data"]) + + const dumpMigrations = mysqlDump(["--no-create-info", "--tables", table]) + + const dumpAll = Effect.map( + Effect.all([dumpSchema, dumpMigrations], { concurrency: 2 }), + ([schema, migrations]) => schema + "\n\n" + migrations + ) + + const dumpFile = (file: string) => + Effect.gen(function*(_) { + const fs = yield* _(FileSystem) + const path = yield* _(Path) + const dump = yield* _(dumpAll) + yield* _(fs.makeDirectory(path.dirname(file), { recursive: true })) + yield* _(fs.writeFileString(file, dump)) + }).pipe( + Effect.mapError((error) => new Migrator.MigrationError({ reason: "failed", message: error.message })) + ) + + return dumpFile(path) + } +}) + +/** + * @category layers + * @since 1.0.0 + */ +export const layer = ( + options: Migrator.MigratorOptions +): Layer.Layer< + never, + SqlError | Migrator.MigrationError, + Client.MysqlClient | FileSystem | Path | CommandExecutor | R +> => Layer.effectDiscard(run(options)) diff --git a/packages/sql-mysql2/src/index.ts b/packages/sql-mysql2/src/index.ts new file mode 100644 index 0000000000..72ae734924 --- /dev/null +++ b/packages/sql-mysql2/src/index.ts @@ -0,0 +1,33 @@ +/** + * @since 1.0.0 + */ + +/** + * @since 1.0.0 + */ +export * as client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * as error from "@effect/sql/Error" + +/** + * @since 1.0.0 + */ +export * as migrator from "./Migrator.js" + +/** + * @since 1.0.0 + */ +export * as resolver from "@effect/sql/Resolver" + +/** + * @since 1.0.0 + */ +export * as schema from "@effect/sql/Schema" + +/** + * @since 1.0.0 + */ +export * as statement from "@effect/sql/Statement" diff --git a/packages/sql-mysql2/test/index.test.ts b/packages/sql-mysql2/test/index.test.ts new file mode 100644 index 0000000000..7c743e0528 --- /dev/null +++ b/packages/sql-mysql2/test/index.test.ts @@ -0,0 +1,8 @@ +import { assert, describe, it } from "vitest" + +// TODO: implement a test suite +describe("sql", () => { + it("should work", () => { + assert.ok(true) + }) +}) diff --git a/packages/sql-mysql2/tsconfig.build.json b/packages/sql-mysql2/tsconfig.build.json new file mode 100644 index 0000000000..808406fd4c --- /dev/null +++ b/packages/sql-mysql2/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.src.json", + "references": [{ "path": "../effect" }, { "path": "../sql" }], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/build.tsbuildinfo", + "outDir": "build/esm", + "declarationDir": "build/dts", + "stripInternal": true + } +} diff --git a/packages/sql-mysql2/tsconfig.examples.json b/packages/sql-mysql2/tsconfig.examples.json new file mode 100644 index 0000000000..119ff192eb --- /dev/null +++ b/packages/sql-mysql2/tsconfig.examples.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["examples"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../experimental" }, + { "path": "../sql" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/examples.tsbuildinfo", + "rootDir": "examples", + "noEmit": true + } +} diff --git a/packages/sql-mysql2/tsconfig.json b/packages/sql-mysql2/tsconfig.json new file mode 100644 index 0000000000..3edbf6b8a5 --- /dev/null +++ b/packages/sql-mysql2/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "include": [], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "tsconfig.test.json" }, + { "path": "tsconfig.examples.json" } + ] +} diff --git a/packages/sql-mysql2/tsconfig.src.json b/packages/sql-mysql2/tsconfig.src.json new file mode 100644 index 0000000000..424a843861 --- /dev/null +++ b/packages/sql-mysql2/tsconfig.src.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src"], + "references": [{ "path": "../effect" }, { "path": "../sql" }], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/src.tsbuildinfo", + "rootDir": "src", + "outDir": "build/src" + } +} diff --git a/packages/sql-mysql2/tsconfig.test.json b/packages/sql-mysql2/tsconfig.test.json new file mode 100644 index 0000000000..497f697f10 --- /dev/null +++ b/packages/sql-mysql2/tsconfig.test.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["test"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../sql" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/test.tsbuildinfo", + "rootDir": "test", + "noEmit": true + } +} diff --git a/packages/sql-mysql2/vitest.config.ts b/packages/sql-mysql2/vitest.config.ts new file mode 100644 index 0000000000..0411095f25 --- /dev/null +++ b/packages/sql-mysql2/vitest.config.ts @@ -0,0 +1,6 @@ +import { mergeConfig, type UserConfigExport } from "vitest/config" +import shared from "../../vitest.shared.js" + +const config: UserConfigExport = {} + +export default mergeConfig(shared, config) diff --git a/packages/sql-pg/LICENSE b/packages/sql-pg/LICENSE new file mode 100644 index 0000000000..7f6fe480f7 --- /dev/null +++ b/packages/sql-pg/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023-present The Contributors + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/packages/sql-pg/README.md b/packages/sql-pg/README.md new file mode 100644 index 0000000000..da09c3b8d6 --- /dev/null +++ b/packages/sql-pg/README.md @@ -0,0 +1,5 @@ +# Effect SQL - Postgresql + +An @effect/sql implementation using the `postgres.js` library. + +See here for more information: https://github.com/Effect-TS/effect/tree/main/packages/sql diff --git a/packages/sql-pg/docgen.json b/packages/sql-pg/docgen.json new file mode 100644 index 0000000000..f980a32f52 --- /dev/null +++ b/packages/sql-pg/docgen.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../node_modules/@effect/docgen/schema.json", + "exclude": [ + "src/internal/**/*.ts" + ] +} diff --git a/packages/sql-pg/examples/resolver.ts b/packages/sql-pg/examples/resolver.ts new file mode 100644 index 0000000000..7459752117 --- /dev/null +++ b/packages/sql-pg/examples/resolver.ts @@ -0,0 +1,88 @@ +import * as DevTools from "@effect/experimental/DevTools" +import * as Schema from "@effect/schema/Schema" +import * as Pg from "@effect/sql-pg" +import { Config, Effect, Layer, String } from "effect" + +class Person extends Schema.Class("Person")({ + id: Schema.Number, + name: Schema.String, + createdAt: Schema.DateFromSelf +}) {} + +const InsertPersonSchema = Schema.Struct(Person.fields).pipe( + Schema.omit("id", "createdAt") +) + +const program = Effect.gen(function*(_) { + const sql = yield* _(Pg.client.PgClient) + + const Insert = yield* _( + Pg.resolver.ordered("InsertPerson", { + Request: InsertPersonSchema, + Result: Person, + execute: (requests) => sql`INSERT INTO people ${sql.insert(requests)} RETURNING people.*` + }) + ) + + const GetById = yield* _( + Pg.resolver.findById("GetPersonById", { + Id: Schema.Number, + Result: Person, + ResultId: (result) => result.id, + execute: (ids) => sql`SELECT * FROM people WHERE id IN ${sql.in(ids)}` + }) + ) + + const GetByName = yield* _( + Pg.resolver.grouped("GetPersonByName", { + Request: Schema.String, + RequestGroupKey: (_) => _, + Result: Person, + ResultGroupKey: (_) => _.name, + execute: (ids) => sql<{}>`SELECT * FROM people WHERE name IN ${sql.in(ids)}` + }) + ) + + const inserted = yield* _( + Effect.all( + [ + Insert.execute({ name: "John Doe" }), + Insert.execute({ name: "Joe Bloggs" }) + ], + { batching: true } + ) + ) + + console.log( + yield* _( + Effect.all( + [GetById.execute(inserted[0].id), GetById.execute(inserted[1].id)], + { batching: true } + ) + ) + ) + + console.log( + yield* _( + Effect.forEach( + ["John Doe", "Joe Bloggs", "John Doe"], + (id) => GetByName.execute(id), + { batching: true } + ) + ) + ) +}) + +const PgLive = Pg.client.layer({ + database: Config.succeed("effect_pg_dev"), + transformQueryNames: Config.succeed(String.camelToSnake), + transformResultNames: Config.succeed(String.snakeToCamel) +}) + +program.pipe( + Effect.provide(PgLive.pipe( + Layer.provide(DevTools.layer()) + )), + Effect.tapErrorCause(Effect.logError), + Effect.runFork +) diff --git a/packages/sql-pg/package.json b/packages/sql-pg/package.json new file mode 100644 index 0000000000..dea84a5a74 --- /dev/null +++ b/packages/sql-pg/package.json @@ -0,0 +1,53 @@ +{ + "name": "@effect/sql-pg", + "version": "0.0.0", + "type": "module", + "license": "MIT", + "description": "A Postgresql toolkit for Effect", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/effect-ts/effect.git", + "directory": "packages/sql-pg" + }, + "bugs": { + "url": "https://github.com/effect-ts/effect/issues" + }, + "tags": [ + "typescript", + "sql", + "database" + ], + "keywords": [ + "typescript", + "sql", + "database" + ], + "publishConfig": { + "access": "public", + "directory": "dist", + "provenance": true + }, + "scripts": { + "build": "pnpm build-esm && pnpm build-cjs && pnpm build-annotate && build-utils pack-v2", + "build-esm": "tsc -b tsconfig.build.json", + "build-cjs": "babel build/esm --plugins @babel/transform-export-namespace-from --plugins @babel/transform-modules-commonjs --out-dir build/cjs --source-maps", + "build-annotate": "babel build --plugins annotate-pure-calls --out-dir build --source-maps", + "check": "tsc -b tsconfig.json", + "test": "vitest", + "coverage": "vitest --coverage" + }, + "devDependencies": { + "@effect/platform": "workspace:^", + "@effect/sql": "workspace:^", + "effect": "workspace:^" + }, + "peerDependencies": { + "@effect/platform": "workspace:^", + "@effect/sql": "workspace:^", + "effect": "workspace:^" + }, + "dependencies": { + "postgres": "^3.4.4" + } +} diff --git a/packages/sql-pg/src/Client.ts b/packages/sql-pg/src/Client.ts new file mode 100644 index 0000000000..5010e3c775 --- /dev/null +++ b/packages/sql-pg/src/Client.ts @@ -0,0 +1,290 @@ +/** + * @since 1.0.0 + */ +import * as Client from "@effect/sql/Client" +import type { Connection } from "@effect/sql/Connection" +import { SqlError } from "@effect/sql/Error" +import type { Custom, Fragment, Primitive } from "@effect/sql/Statement" +import * as Statement from "@effect/sql/Statement" +import * as Chunk from "effect/Chunk" +import * as Config from "effect/Config" +import type { ConfigError } from "effect/ConfigError" +import * as Context from "effect/Context" +import * as Duration from "effect/Duration" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import type { Scope } from "effect/Scope" +import * as Secret from "effect/Secret" +import * as Stream from "effect/Stream" +import type { PendingQuery, PendingValuesQuery } from "postgres" +import postgres from "postgres" + +/** + * @category models + * @since 1.0.0 + */ +export interface PgClient extends Client.Client { + readonly config: PgClientConfig + readonly json: (_: unknown) => Fragment + readonly array: (_: ReadonlyArray) => Fragment +} + +/** + * @category tags + * @since 1.0.0 + */ +export const PgClient: Context.Tag = Context.GenericTag("@effect/sql-pg/PgClient") + +/** + * @category constructors + * @since 1.0.0 + */ +export interface PgClientConfig { + readonly url?: Secret.Secret | undefined + + readonly host?: string | undefined + readonly port?: number | undefined + readonly path?: string | undefined + readonly ssl?: boolean | undefined + readonly database?: string | undefined + readonly username?: string | undefined + readonly password?: Secret.Secret | undefined + + readonly idleTimeout?: Duration.DurationInput | undefined + readonly connectTimeout?: Duration.DurationInput | undefined + + readonly maxConnections?: number | undefined + readonly connectionTTL?: Duration.DurationInput | undefined + + readonly transformResultNames?: ((str: string) => string) | undefined + readonly transformQueryNames?: ((str: string) => string) | undefined + readonly transformJson?: boolean | undefined + readonly fetchTypes?: boolean | undefined + + readonly debug?: postgres.Options<{}>["debug"] | undefined +} + +const escape = Statement.defaultEscape("\"") + +type PartialWithUndefined = { [K in keyof T]?: T[K] | undefined } + +/** + * @category constructors + * @since 1.0.0 + */ +export const make = ( + options: PgClientConfig +): Effect.Effect => + Effect.gen(function*(_) { + const compiler = makeCompiler( + options.transformQueryNames, + options.transformJson + ) + + const transformRows = Client.defaultTransforms( + options.transformResultNames!, + options.transformJson + ).array + + const opts: PartialWithUndefined> = { + max: options.maxConnections ?? 10, + max_lifetime: options.connectionTTL + ? Math.round( + Duration.toMillis(Duration.decode(options.connectionTTL)) / 1000 + ) + : undefined, + idle_timeout: options.idleTimeout + ? Math.round( + Duration.toMillis(Duration.decode(options.idleTimeout)) / 1000 + ) + : undefined, + connect_timeout: options.connectTimeout + ? Math.round( + Duration.toMillis(Duration.decode(options.connectTimeout)) / 1000 + ) + : undefined, + + host: options.host, + port: options.port, + ssl: options.ssl, + path: options.path, + database: options.database, + username: options.username, + password: options.password ? Secret.value(options.password) : undefined, + fetch_types: options.fetchTypes ?? true, + debug: options.debug + } + + const client = options.url + ? postgres(Secret.value(options.url), opts as any) + : postgres(opts as any) + + yield* _(Effect.addFinalizer(() => Effect.promise(() => client.end()))) + + class ConnectionImpl implements Connection { + constructor(private readonly pg: postgres.Sql<{}>) {} + + private run(query: PendingQuery | PendingValuesQuery) { + return Effect.async, SqlError>((resume) => { + query.then( + (_) => resume(Effect.succeed(_)), + (error) => resume(new SqlError({ error })) + ) + return Effect.sync(() => query.cancel()) + }) + } + + private runTransform(query: PendingQuery) { + return options.transformResultNames + ? Effect.map(this.run(query), transformRows) + : this.run(query) + } + + execute(sql: string, params: ReadonlyArray) { + return this.runTransform(this.pg.unsafe(sql, params as any)) + } + executeWithoutTransform(sql: string, params: ReadonlyArray) { + return this.run(this.pg.unsafe(sql, params as any)) + } + executeValues(sql: string, params: ReadonlyArray) { + return this.run(this.pg.unsafe(sql, params as any).values()) + } + executeRaw(sql: string, params?: ReadonlyArray) { + return this.runTransform(this.pg.unsafe(sql, params as any)) + } + executeStream(sql: string, params: ReadonlyArray) { + return Stream.mapChunks( + Stream.fromAsyncIterable( + this.pg.unsafe(sql, params as any).cursor(16) as AsyncIterable< + Array + >, + (error) => new SqlError({ error }) + ), + Chunk.flatMap((rows) => + Chunk.unsafeFromArray( + options.transformResultNames ? transformRows(rows) : rows + ) + ) + ) + } + } + + return Object.assign( + Client.make({ + acquirer: Effect.succeed(new ConnectionImpl(client)), + transactionAcquirer: Effect.map( + Effect.acquireRelease( + Effect.tryPromise({ + try: () => client.reserve(), + catch: (error) => new SqlError({ error }) + }), + (pg) => Effect.sync(() => pg.release()) + ), + (_) => new ConnectionImpl(_) + ), + compiler + }), + { + config: options, + json: (_: unknown) => PgJson(_), + array: (_: ReadonlyArray) => PgArray(_) + } + ) + }) + +/** + * @category constructor + * @since 1.0.0 + */ +export const layer: ( + config: Config.Config.Wrap +) => Layer.Layer = ( + config: Config.Config.Wrap +) => Layer.scoped(PgClient, Effect.flatMap(Config.unwrap(config), make)) + +/** + * @category constructor + * @since 1.0.0 + */ +export const makeCompiler = ( + transform?: (_: string) => string, + transformJson = true +): Statement.Compiler => { + const pg = postgres({ max: 0 }) + + const transformValue = transformJson && transform + ? Client.defaultTransforms(transform).value + : undefined + + return Statement.makeCompiler({ + placeholder: (_) => `$${_}`, + onIdentifier: transform ? (_) => escape(transform(_)) : escape, + onRecordUpdate: (placeholders, valueAlias, valueColumns, values) => [ + `(values ${placeholders}) AS ${valueAlias}${valueColumns}`, + values.flat() + ], + onCustom: (type, placeholder) => { + switch (type.kind) { + case "PgJson": { + return [ + placeholder(), + [ + pg.json( + transformValue !== undefined + ? transformValue(type.i0) + : type.i0 + ) as any + ] + ] + } + case "PgArray": { + const param = pg.array(type.i0 as any) as any + const first = type.i0[0] + switch (typeof first) { + case "boolean": { + param.type = 1000 + break + } + case "number": { + param.type = 1022 + break + } + default: { + param.type = 1009 + break + } + } + return [placeholder(), [param]] + } + } + } + }) +} + +/** + * @category custom types + * @since 1.0.0 + */ +export type PgCustom = PgJson | PgArray + +/** + * @category custom types + * @since 1.0.0 + */ +interface PgJson extends Custom<"PgJson", unknown> {} +/** + * @category custom types + * @since 1.0.0 + */ +const PgJson = Statement.custom("PgJson") + +/** + * @category custom types + * @since 1.0.0 + */ +interface PgArray extends Custom<"PgArray", ReadonlyArray> {} +/** + * @category custom types + * @since 1.0.0 + */ +const PgArray = Statement.custom("PgArray") diff --git a/packages/sql-pg/src/Migrator.ts b/packages/sql-pg/src/Migrator.ts new file mode 100644 index 0000000000..9f160cdda9 --- /dev/null +++ b/packages/sql-pg/src/Migrator.ts @@ -0,0 +1,113 @@ +/** + * @since 1.0.0 + */ +import * as Command from "@effect/platform/Command" +import type { CommandExecutor } from "@effect/platform/CommandExecutor" +import { FileSystem } from "@effect/platform/FileSystem" +import { Path } from "@effect/platform/Path" +import type { SqlError } from "@effect/sql/Error" +import * as Migrator from "@effect/sql/Migrator" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import * as Secret from "effect/Secret" +import * as Client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * from "@effect/sql/Migrator" + +/** + * @category constructor + * @since 1.0.0 + */ +export const run: ( + options: Migrator.MigratorOptions +) => Effect.Effect< + ReadonlyArray, + SqlError | Migrator.MigrationError, + Client.PgClient | FileSystem | Path | CommandExecutor | R +> = Migrator.make({ + getClient: Client.PgClient, + ensureTable(sql, table) { + return Effect.catchAll( + sql`select ${table}::regclass`, + () => + sql` + CREATE TABLE ${sql(table)} ( + migration_id integer primary key, + created_at timestamp with time zone not null default now(), + name text not null + ) + ` + ) + }, + lockTable(sql, table) { + return sql` + LOCK TABLE ${sql(table)} IN ACCESS EXCLUSIVE MODE + ` + }, + dumpSchema(sql, path, table) { + const pgDump = (args: Array) => + Effect.gen(function*(_) { + const dump = yield* _( + Command.make("pg_dump", ...args, "--no-owner", "--no-privileges"), + Command.env({ + PATH: (globalThis as any).process?.env.PATH, + PGHOST: sql.config.host, + PGPORT: sql.config.port?.toString(), + PGUSER: sql.config.username, + PGPASSWORD: sql.config.password + ? Secret.value(sql.config.password) + : undefined, + PGDATABASE: sql.config.database, + PGSSLMODE: sql.config.ssl ? "require" : "prefer" + }), + Command.string + ) + + return dump.replace(/^--.*$/gm, "") + .replace(/^SET .*$/gm, "") + .replace(/^SELECT pg_catalog\..*$/gm, "") + .replace(/\n{2,}/gm, "\n\n") + .trim() + }).pipe( + Effect.mapError((error) => new Migrator.MigrationError({ reason: "failed", message: error.message })) + ) + + const pgDumpSchema = pgDump(["--schema-only"]) + + const pgDumpMigrations = pgDump([ + "--column-inserts", + "--data-only", + `--table=${table}` + ]) + + const pgDumpAll = Effect.map( + Effect.all([pgDumpSchema, pgDumpMigrations], { concurrency: 2 }), + ([schema, migrations]) => schema + "\n\n" + migrations + ) + + const pgDumpFile = (path: string) => + Effect.gen(function*(_) { + const fs = yield* _(FileSystem) + const path_ = yield* _(Path) + const dump = yield* _(pgDumpAll) + yield* _(fs.makeDirectory(path_.dirname(path), { recursive: true })) + yield* _(fs.writeFileString(path, dump)) + }).pipe( + Effect.mapError((error) => new Migrator.MigrationError({ reason: "failed", message: error.message })) + ) + + return pgDumpFile(path) + } +}) + +/** + * @category layers + * @since 1.0.0 + */ +export const layer = ( + options: Migrator.MigratorOptions +): Layer.Layer => + Layer.effectDiscard(run(options)) diff --git a/packages/sql-pg/src/index.ts b/packages/sql-pg/src/index.ts new file mode 100644 index 0000000000..72ae734924 --- /dev/null +++ b/packages/sql-pg/src/index.ts @@ -0,0 +1,33 @@ +/** + * @since 1.0.0 + */ + +/** + * @since 1.0.0 + */ +export * as client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * as error from "@effect/sql/Error" + +/** + * @since 1.0.0 + */ +export * as migrator from "./Migrator.js" + +/** + * @since 1.0.0 + */ +export * as resolver from "@effect/sql/Resolver" + +/** + * @since 1.0.0 + */ +export * as schema from "@effect/sql/Schema" + +/** + * @since 1.0.0 + */ +export * as statement from "@effect/sql/Statement" diff --git a/packages/sql-pg/test/Client.test.ts b/packages/sql-pg/test/Client.test.ts new file mode 100644 index 0000000000..b9414d4cc8 --- /dev/null +++ b/packages/sql-pg/test/Client.test.ts @@ -0,0 +1,158 @@ +import * as Sql from "@effect/sql-pg" +import { defaultTransforms } from "@effect/sql/Client" +import { Effect, Scope, String } from "effect" +import { assert, describe, expect, it } from "vitest" + +const sql = Effect.runSync(Scope.extend(Sql.client.make({}), Effect.runSync(Scope.make()))) +const compiler = Sql.client.makeCompiler() +const compilerTransform = Sql.client.makeCompiler(String.camelToSnake) +const transformsNested = defaultTransforms(String.snakeToCamel) +const transforms = defaultTransforms(String.snakeToCamel, false) + +describe("pg", () => { + it("insert helper", () => { + const [query, params] = compiler.compile( + sql`INSERT INTO people ${sql.insert({ name: "Tim", age: 10 })}` + ) + expect(query).toEqual(`INSERT INTO people ("name","age") VALUES ($1,$2)`) + expect(params).toEqual(["Tim", 10]) + }) + + it("update helper", () => { + const [query, params] = compiler.compile( + sql`UPDATE people SET name = data.name FROM ${ + sql.updateValues( + [{ name: "Tim" }, { name: "John" }], + "data" + ) + }` + ) + expect(query).toEqual( + `UPDATE people SET name = data.name FROM (values ($1),($2)) AS data("name")` + ) + expect(params).toEqual(["Tim", "John"]) + }) + + it("array helper", () => { + const [query, params] = compiler.compile( + sql`SELECT * FROM ${sql("people")} WHERE id IN ${sql.in([1, 2, "string"])}` + ) + expect(query).toEqual(`SELECT * FROM "people" WHERE id IN ($1,$2,$3)`) + expect(params).toEqual([1, 2, "string"]) + }) + + it("json", () => { + const [query, params] = compiler.compile(sql`SELECT ${sql.json({ a: 1 })}`) + expect(query).toEqual(`SELECT $1`) + expect((params[0] as any).type).toEqual(3802) + }) + + it("json transform", () => { + const [query, params] = compilerTransform.compile( + sql`SELECT ${sql.json({ aKey: 1 })}` + ) + expect(query).toEqual(`SELECT $1`) + assert.deepEqual((params[0] as any).value, { a_key: 1 }) + }) + + it("array", () => { + const [query, params] = compiler.compile( + sql`SELECT ${sql.array([1, 2, 3])}` + ) + expect(query).toEqual(`SELECT $1`) + expect((params[0] as any).value).toEqual([1, 2, 3]) + }) + + it("transform nested", () => { + assert.deepEqual( + transformsNested.array([ + { + a_key: 1, + nested: [{ b_key: 2 }], + arr_primitive: [1, "2", true] + } + ]) as any, + [ + { + aKey: 1, + nested: [{ bKey: 2 }], + arrPrimitive: [1, "2", true] + } + ] + ) + }) + + it("transform non nested", () => { + assert.deepEqual( + transforms.array([ + { + a_key: 1, + nested: [{ b_key: 2 }], + arr_primitive: [1, "2", true] + } + ]) as any, + [ + { + aKey: 1, + nested: [{ b_key: 2 }], + arrPrimitive: [1, "2", true] + } + ] + ) + + assert.deepEqual( + transforms.array([ + { + json_field: { + test_value: [1, true, null, "text"], + test_nested: { + test_value: [1, true, null, "text"] + } + } + } + ]) as any, + [ + { + jsonField: { + test_value: [1, true, null, "text"], + test_nested: { + test_value: [1, true, null, "text"] + } + } + } + ] + ) + }) + + it("insert fragments", () => { + const [query, params] = sql`INSERT INTO people ${ + sql.insert({ + name: "Tim", + age: 10, + json: sql.json({ a: 1 }) + }) + }`.compile() + assert.strictEqual( + query, + "INSERT INTO people (\"name\",\"age\",\"json\") VALUES ($1,$2,$3)" + ) + assert.lengthOf(params, 3) + expect((params[2] as any).type).toEqual(3802) + }) + + it("insert array", () => { + const [query, params] = sql`INSERT INTO people ${ + sql.insert({ + name: "Tim", + age: 10, + array: sql.array([1, 2, 3]) + }) + }`.compile() + assert.strictEqual( + query, + "INSERT INTO people (\"name\",\"age\",\"array\") VALUES ($1,$2,$3)" + ) + assert.lengthOf(params, 3) + expect((params[2] as any).type).toEqual(1022) + }) +}) diff --git a/packages/sql-pg/tsconfig.build.json b/packages/sql-pg/tsconfig.build.json new file mode 100644 index 0000000000..808406fd4c --- /dev/null +++ b/packages/sql-pg/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.src.json", + "references": [{ "path": "../effect" }, { "path": "../sql" }], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/build.tsbuildinfo", + "outDir": "build/esm", + "declarationDir": "build/dts", + "stripInternal": true + } +} diff --git a/packages/sql-pg/tsconfig.examples.json b/packages/sql-pg/tsconfig.examples.json new file mode 100644 index 0000000000..119ff192eb --- /dev/null +++ b/packages/sql-pg/tsconfig.examples.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["examples"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../experimental" }, + { "path": "../sql" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/examples.tsbuildinfo", + "rootDir": "examples", + "noEmit": true + } +} diff --git a/packages/sql-pg/tsconfig.json b/packages/sql-pg/tsconfig.json new file mode 100644 index 0000000000..3edbf6b8a5 --- /dev/null +++ b/packages/sql-pg/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "include": [], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "tsconfig.test.json" }, + { "path": "tsconfig.examples.json" } + ] +} diff --git a/packages/sql-pg/tsconfig.src.json b/packages/sql-pg/tsconfig.src.json new file mode 100644 index 0000000000..424a843861 --- /dev/null +++ b/packages/sql-pg/tsconfig.src.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src"], + "references": [{ "path": "../effect" }, { "path": "../sql" }], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/src.tsbuildinfo", + "rootDir": "src", + "outDir": "build/src" + } +} diff --git a/packages/sql-pg/tsconfig.test.json b/packages/sql-pg/tsconfig.test.json new file mode 100644 index 0000000000..497f697f10 --- /dev/null +++ b/packages/sql-pg/tsconfig.test.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["test"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../sql" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/test.tsbuildinfo", + "rootDir": "test", + "noEmit": true + } +} diff --git a/packages/sql-pg/vitest.config.ts b/packages/sql-pg/vitest.config.ts new file mode 100644 index 0000000000..0411095f25 --- /dev/null +++ b/packages/sql-pg/vitest.config.ts @@ -0,0 +1,6 @@ +import { mergeConfig, type UserConfigExport } from "vitest/config" +import shared from "../../vitest.shared.js" + +const config: UserConfigExport = {} + +export default mergeConfig(shared, config) diff --git a/packages/sql-sqlite-bun/LICENSE b/packages/sql-sqlite-bun/LICENSE new file mode 100644 index 0000000000..7f6fe480f7 --- /dev/null +++ b/packages/sql-sqlite-bun/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023-present The Contributors + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/packages/sql-sqlite-bun/README.md b/packages/sql-sqlite-bun/README.md new file mode 100644 index 0000000000..877523bf4b --- /dev/null +++ b/packages/sql-sqlite-bun/README.md @@ -0,0 +1,5 @@ +# Effect SQL - SQLite + +An @effect/sql implementation using the `bun:sqlite` library. + +See here for more information: https://github.com/Effect-TS/effect/tree/main/packages/sql diff --git a/packages/sql-sqlite-bun/docgen.json b/packages/sql-sqlite-bun/docgen.json new file mode 100644 index 0000000000..f980a32f52 --- /dev/null +++ b/packages/sql-sqlite-bun/docgen.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../node_modules/@effect/docgen/schema.json", + "exclude": [ + "src/internal/**/*.ts" + ] +} diff --git a/packages/sql-sqlite-bun/examples/Client.test.ts b/packages/sql-sqlite-bun/examples/Client.test.ts new file mode 100644 index 0000000000..83c2291494 --- /dev/null +++ b/packages/sql-sqlite-bun/examples/Client.test.ts @@ -0,0 +1,30 @@ +import { BunFileSystem } from "@effect/platform-bun" +import { FileSystem } from "@effect/platform/FileSystem" +import * as Sql from "@effect/sql-sqlite-bun" +import { describe, expect, test } from "bun:test" +import { Effect } from "effect" + +const makeClient = Effect.gen(function*(_) { + const fs = yield* _(FileSystem) + const dir = yield* _(fs.makeTempDirectoryScoped()) + return yield* _(Sql.client.make({ + filename: dir + "/test.db" + })) +}).pipe(Effect.provide(BunFileSystem.layer)) + +describe("Client", () => { + test("works", () => + Effect.gen(function*(_) { + const sql = yield* _(makeClient) + yield* _(sql`CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)`) + yield* _(sql`INSERT INTO test (name) VALUES ('hello')`) + let rows = yield* _(sql`SELECT * FROM test`) + expect(rows).toEqual([{ id: 1, name: "hello" }]) + yield* _(sql`INSERT INTO test (name) VALUES ('world')`, sql.withTransaction) + rows = yield* _(sql`SELECT * FROM test`) + expect(rows).toEqual([ + { id: 1, name: "hello" }, + { id: 2, name: "world" } + ]) + }).pipe(Effect.scoped, Effect.runPromise)) +}) diff --git a/packages/sql-sqlite-bun/package.json b/packages/sql-sqlite-bun/package.json new file mode 100644 index 0000000000..6551730976 --- /dev/null +++ b/packages/sql-sqlite-bun/package.json @@ -0,0 +1,51 @@ +{ + "name": "@effect/sql-sqlite-bun", + "version": "0.0.0", + "type": "module", + "license": "MIT", + "description": "A SQLite toolkit for Effect", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/effect-ts/effect.git", + "directory": "packages/sql-sqlite-bun" + }, + "bugs": { + "url": "https://github.com/effect-ts/effect/issues" + }, + "tags": [ + "typescript", + "sql", + "database" + ], + "keywords": [ + "typescript", + "sql", + "database" + ], + "publishConfig": { + "access": "public", + "directory": "dist", + "provenance": true + }, + "scripts": { + "build": "pnpm build-esm && pnpm build-cjs && pnpm build-annotate && build-utils pack-v2", + "build-esm": "tsc -b tsconfig.build.json", + "build-cjs": "babel build/esm --plugins @babel/transform-export-namespace-from --plugins @babel/transform-modules-commonjs --out-dir build/cjs --source-maps", + "build-annotate": "babel build --plugins annotate-pure-calls --out-dir build --source-maps", + "check": "tsc -b tsconfig.json", + "test": "vitest", + "coverage": "vitest --coverage" + }, + "devDependencies": { + "@effect/platform": "workspace:^", + "@effect/sql": "workspace:^", + "bun-types": "1.0.33", + "effect": "workspace:^" + }, + "peerDependencies": { + "@effect/platform": "workspace:^", + "@effect/sql": "workspace:^", + "effect": "workspace:^" + } +} diff --git a/packages/sql-sqlite-bun/src/Client.ts b/packages/sql-sqlite-bun/src/Client.ts new file mode 100644 index 0000000000..1b3ec98fa1 --- /dev/null +++ b/packages/sql-sqlite-bun/src/Client.ts @@ -0,0 +1,185 @@ +/** + * @since 1.0.0 + */ +import * as Client from "@effect/sql/Client" +import type { Connection } from "@effect/sql/Connection" +import { SqlError } from "@effect/sql/Error" +import * as Statement from "@effect/sql/Statement" +import { Database } from "bun:sqlite" +import * as Config from "effect/Config" +import type { ConfigError } from "effect/ConfigError" +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import { identity } from "effect/Function" +import * as Layer from "effect/Layer" +import * as Scope from "effect/Scope" + +/** + * @category models + * @since 1.0.0 + */ +export interface SqliteClient extends Client.Client { + readonly config: SqliteClientConfig + readonly export: Effect.Effect + readonly loadExtension: (path: string) => Effect.Effect +} + +/** + * @category tags + * @since 1.0.0 + */ +export const SqliteClient: Context.Tag = Context.GenericTag( + "@effect/sql-sqlite-bun/SqliteClient" +) + +/** + * @category models + * @since 1.0.0 + */ +export interface SqliteClientConfig { + readonly filename: string + readonly readonly?: boolean | undefined + readonly create?: boolean | undefined + readonly readwrite?: boolean | undefined + readonly disableWAL?: boolean | undefined + + readonly transformResultNames?: ((str: string) => string) | undefined + readonly transformQueryNames?: ((str: string) => string) | undefined +} + +interface SqliteConnection extends Connection { + readonly export: Effect.Effect + readonly loadExtension: (path: string) => Effect.Effect +} + +/** + * @category constructor + * @since 1.0.0 + */ +export const make = ( + options: SqliteClientConfig +): Effect.Effect => + Effect.gen(function*(_) { + const compiler = makeCompiler(options.transformQueryNames) + const transformRows = Client.defaultTransforms( + options.transformResultNames! + ).array + + const makeConnection = Effect.gen(function*(_) { + const db = new Database(options.filename, { + readonly: options.readonly, + readwrite: options.readwrite ?? true, + create: options.create ?? true + } as any) + yield* _(Effect.addFinalizer(() => Effect.sync(() => db.close()))) + + if (options.disableWAL !== true) { + db.run("PRAGMA journal_mode = WAL;") + } + + const run = ( + sql: string, + params: ReadonlyArray = [] + ) => + Effect.try({ + try: () => db.query(sql).all(...(params as any)) as Array, + catch: (error) => new SqlError({ error }) + }) + + const runTransform = options.transformResultNames + ? (sql: string, params?: ReadonlyArray) => Effect.map(run(sql, params), transformRows) + : run + + const runValues = ( + sql: string, + params: ReadonlyArray = [] + ) => + Effect.try({ + try: () => db.query(sql).values(...(params as any)) as Array, + catch: (error) => new SqlError({ error }) + }) + + return identity({ + execute(sql, params) { + return runTransform(sql, params) + }, + executeValues(sql, params) { + return runValues(sql, params) + }, + executeWithoutTransform(sql, params) { + return run(sql, params) + }, + executeRaw(sql, params) { + return runTransform(sql, params) + }, + executeStream(_sql, _params) { + return Effect.dieMessage("executeStream not implemented") + }, + export: Effect.try({ + try: () => db.serialize(), + catch: (error) => new SqlError({ error }) + }), + loadExtension: (path) => + Effect.try({ + try: () => db.loadExtension(path), + catch: (error) => new SqlError({ error }) + }) + }) + }) + + const semaphore = yield* _(Effect.makeSemaphore(1)) + const connection = yield* _(makeConnection) + + const acquirer = semaphore.withPermits(1)(Effect.succeed(connection)) + const transactionAcquirer = Effect.uninterruptibleMask((restore) => + Effect.as( + Effect.zipRight( + restore(semaphore.take(1)), + Effect.tap( + Effect.scope, + (scope) => Scope.addFinalizer(scope, semaphore.release(1)) + ) + ), + connection + ) + ) + + return Object.assign( + Client.make({ + acquirer, + compiler, + transactionAcquirer + }), + { + config: options, + export: Effect.flatMap(acquirer, (_) => _.export), + loadExtension: (path: string) => Effect.flatMap(acquirer, (_) => _.loadExtension(path)) + } + ) + }) + +/** + * @category layers + * @since 1.0.0 + */ +export const layer = ( + config: Config.Config.Wrap +): Layer.Layer => + Layer.scoped( + SqliteClient, + Effect.flatMap(Config.unwrap(config), make) + ) + +const escape = Statement.defaultEscape("\"") + +/** + * @category compiler + * @since 1.0.0 + */ +export const makeCompiler = (transform?: (_: string) => string) => + Statement.makeCompiler({ + placeholder: (_) => `?`, + onIdentifier: transform ? (_) => escape(transform(_)) : escape, + onRecordUpdate: () => ["", []], + onCustom: () => ["", []] + }) diff --git a/packages/sql-sqlite-bun/src/Migrator.ts b/packages/sql-sqlite-bun/src/Migrator.ts new file mode 100644 index 0000000000..e5446ecbfe --- /dev/null +++ b/packages/sql-sqlite-bun/src/Migrator.ts @@ -0,0 +1,89 @@ +/** + * @since 1.0.0 + */ +import * as Command from "@effect/platform/Command" +import type { CommandExecutor } from "@effect/platform/CommandExecutor" +import { FileSystem } from "@effect/platform/FileSystem" +import { Path } from "@effect/platform/Path" +import type { SqlError } from "@effect/sql/Error" +import * as Migrator from "@effect/sql/Migrator" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import * as Client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * from "@effect/sql/Migrator" + +/** + * @category constructor + * @since 1.0.0 + */ +export const run: ( + options: Migrator.MigratorOptions +) => Effect.Effect< + ReadonlyArray, + SqlError | Migrator.MigrationError, + Client.SqliteClient | R | FileSystem | Path | CommandExecutor +> = Migrator.make({ + getClient: Client.SqliteClient, + ensureTable(sql, table) { + return sql` + CREATE TABLE IF NOT EXISTS ${sql(table)} ( + migration_id integer PRIMARY KEY NOT NULL, + created_at datetime NOT NULL DEFAULT current_timestamp, + name VARCHAR(255) NOT NULL + ) + ` + }, + dumpSchema(sql, path, table) { + const dump = (args: Array) => + Effect.gen(function*(_) { + const dump = yield* _( + Command.make("sqlite3", sql.config.filename, ...args), + Command.string + ) + return dump.replace(/^create table sqlite_sequence\(.*$/im, "") + .replace(/\n{2,}/gm, "\n\n") + .trim() + }).pipe( + Effect.mapError((error) => new Migrator.MigrationError({ reason: "failed", message: error.message })) + ) + + const dumpSchema = dump([".schema"]) + + const dumpMigrations = dump([ + "--cmd", + `.mode insert ${table}`, + `select * from ${table}` + ]) + + const dumpAll = Effect.map( + Effect.all([dumpSchema, dumpMigrations], { concurrency: 2 }), + ([schema, migrations]) => schema + "\n\n" + migrations + ) + + const dumpFile = (file: string) => + Effect.gen(function*(_) { + const fs = yield* _(FileSystem) + const path = yield* _(Path) + const dump = yield* _(dumpAll) + yield* _(fs.makeDirectory(path.dirname(file), { recursive: true })) + yield* _(fs.writeFileString(file, dump)) + }).pipe( + Effect.mapError((error) => new Migrator.MigrationError({ reason: "failed", message: error.message })) + ) + + return dumpFile(path) + } +}) + +/** + * @category constructor + * @since 1.0.0 + */ +export const makeLayer = ( + options: Migrator.MigratorOptions +): Layer.Layer => + Layer.effectDiscard(run(options)) diff --git a/packages/sql-sqlite-bun/src/index.ts b/packages/sql-sqlite-bun/src/index.ts new file mode 100644 index 0000000000..72ae734924 --- /dev/null +++ b/packages/sql-sqlite-bun/src/index.ts @@ -0,0 +1,33 @@ +/** + * @since 1.0.0 + */ + +/** + * @since 1.0.0 + */ +export * as client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * as error from "@effect/sql/Error" + +/** + * @since 1.0.0 + */ +export * as migrator from "./Migrator.js" + +/** + * @since 1.0.0 + */ +export * as resolver from "@effect/sql/Resolver" + +/** + * @since 1.0.0 + */ +export * as schema from "@effect/sql/Schema" + +/** + * @since 1.0.0 + */ +export * as statement from "@effect/sql/Statement" diff --git a/packages/sql-sqlite-bun/test/Client.test.ts b/packages/sql-sqlite-bun/test/Client.test.ts new file mode 100644 index 0000000000..653e64614d --- /dev/null +++ b/packages/sql-sqlite-bun/test/Client.test.ts @@ -0,0 +1,6 @@ +import { describe, it } from "@effect/vitest" +import { Effect } from "effect" + +describe("Client", () => { + it.effect("should work", () => Effect.unit) +}) diff --git a/packages/sql-sqlite-bun/tsconfig.build.json b/packages/sql-sqlite-bun/tsconfig.build.json new file mode 100644 index 0000000000..808406fd4c --- /dev/null +++ b/packages/sql-sqlite-bun/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.src.json", + "references": [{ "path": "../effect" }, { "path": "../sql" }], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/build.tsbuildinfo", + "outDir": "build/esm", + "declarationDir": "build/dts", + "stripInternal": true + } +} diff --git a/packages/sql-sqlite-bun/tsconfig.examples.json b/packages/sql-sqlite-bun/tsconfig.examples.json new file mode 100644 index 0000000000..7e7ba56bd3 --- /dev/null +++ b/packages/sql-sqlite-bun/tsconfig.examples.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["examples"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../experimental" }, + { "path": "../platform-bun" }, + { "path": "../sql" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/examples.tsbuildinfo", + "rootDir": "examples", + "noEmit": true, + "types": ["bun-types"] + } +} diff --git a/packages/sql-sqlite-bun/tsconfig.json b/packages/sql-sqlite-bun/tsconfig.json new file mode 100644 index 0000000000..3edbf6b8a5 --- /dev/null +++ b/packages/sql-sqlite-bun/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "include": [], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "tsconfig.test.json" }, + { "path": "tsconfig.examples.json" } + ] +} diff --git a/packages/sql-sqlite-bun/tsconfig.src.json b/packages/sql-sqlite-bun/tsconfig.src.json new file mode 100644 index 0000000000..8eef996247 --- /dev/null +++ b/packages/sql-sqlite-bun/tsconfig.src.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src", "../sql-sqlite-wasm/src/sqlite-wasm.d.ts"], + "references": [{ "path": "../effect" }, { "path": "../sql" }], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/src.tsbuildinfo", + "rootDir": "src", + "outDir": "build/src", + "types": ["bun-types"] + } +} diff --git a/packages/sql-sqlite-bun/tsconfig.test.json b/packages/sql-sqlite-bun/tsconfig.test.json new file mode 100644 index 0000000000..41d4485611 --- /dev/null +++ b/packages/sql-sqlite-bun/tsconfig.test.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["test"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../platform-bun" }, + { "path": "../sql" }, + { "path": "../vitest" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/test.tsbuildinfo", + "rootDir": "test", + "noEmit": true, + "types": ["bun-types"] + } +} diff --git a/packages/sql-sqlite-bun/vitest.config.ts b/packages/sql-sqlite-bun/vitest.config.ts new file mode 100644 index 0000000000..0411095f25 --- /dev/null +++ b/packages/sql-sqlite-bun/vitest.config.ts @@ -0,0 +1,6 @@ +import { mergeConfig, type UserConfigExport } from "vitest/config" +import shared from "../../vitest.shared.js" + +const config: UserConfigExport = {} + +export default mergeConfig(shared, config) diff --git a/packages/sql-sqlite-node/LICENSE b/packages/sql-sqlite-node/LICENSE new file mode 100644 index 0000000000..7f6fe480f7 --- /dev/null +++ b/packages/sql-sqlite-node/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023-present The Contributors + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/packages/sql-sqlite-node/README.md b/packages/sql-sqlite-node/README.md new file mode 100644 index 0000000000..bbb375c9fb --- /dev/null +++ b/packages/sql-sqlite-node/README.md @@ -0,0 +1,5 @@ +# Effect SQL - SQLite + +An @effect/sql implementation using the `better-sqlite3` library. + +See here for more information: https://github.com/Effect-TS/effect/tree/main/packages/sql diff --git a/packages/sql-sqlite-node/docgen.json b/packages/sql-sqlite-node/docgen.json new file mode 100644 index 0000000000..f980a32f52 --- /dev/null +++ b/packages/sql-sqlite-node/docgen.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../node_modules/@effect/docgen/schema.json", + "exclude": [ + "src/internal/**/*.ts" + ] +} diff --git a/packages/sql-sqlite-node/package.json b/packages/sql-sqlite-node/package.json new file mode 100644 index 0000000000..fabf5b960a --- /dev/null +++ b/packages/sql-sqlite-node/package.json @@ -0,0 +1,54 @@ +{ + "name": "@effect/sql-sqlite-node", + "version": "0.0.0", + "type": "module", + "license": "MIT", + "description": "A SQLite toolkit for Effect", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/effect-ts/effect.git", + "directory": "packages/sql-sqlite-node" + }, + "bugs": { + "url": "https://github.com/effect-ts/effect/issues" + }, + "tags": [ + "typescript", + "sql", + "database" + ], + "keywords": [ + "typescript", + "sql", + "database" + ], + "publishConfig": { + "access": "public", + "directory": "dist", + "provenance": true + }, + "scripts": { + "build": "pnpm build-esm && pnpm build-cjs && pnpm build-annotate && build-utils pack-v2", + "build-esm": "tsc -b tsconfig.build.json", + "build-cjs": "babel build/esm --plugins @babel/transform-export-namespace-from --plugins @babel/transform-modules-commonjs --out-dir build/cjs --source-maps", + "build-annotate": "babel build --plugins annotate-pure-calls --out-dir build --source-maps", + "check": "tsc -b tsconfig.json", + "test": "vitest", + "coverage": "vitest --coverage" + }, + "devDependencies": { + "@effect/platform": "workspace:^", + "@effect/sql": "workspace:^", + "@types/better-sqlite3": "^7.6.9", + "effect": "workspace:^" + }, + "peerDependencies": { + "@effect/platform": "workspace:^", + "@effect/sql": "workspace:^", + "effect": "workspace:^" + }, + "dependencies": { + "better-sqlite3": "^9.5.0" + } +} diff --git a/packages/sql-sqlite-node/src/Client.ts b/packages/sql-sqlite-node/src/Client.ts new file mode 100644 index 0000000000..f910bdf50c --- /dev/null +++ b/packages/sql-sqlite-node/src/Client.ts @@ -0,0 +1,218 @@ +/** + * @since 1.0.0 + */ +import * as Client from "@effect/sql/Client" +import type { Connection } from "@effect/sql/Connection" +import { SqlError } from "@effect/sql/Error" +import * as Statement from "@effect/sql/Statement" +import Sqlite from "better-sqlite3" +import * as Cache from "effect/Cache" +import * as Config from "effect/Config" +import type { ConfigError } from "effect/ConfigError" +import * as Context from "effect/Context" +import * as Duration from "effect/Duration" +import * as Effect from "effect/Effect" +import { identity } from "effect/Function" +import * as Layer from "effect/Layer" +import * as Scope from "effect/Scope" + +/** + * @category models + * @since 1.0.0 + */ +export interface SqliteClient extends Client.Client { + readonly config: SqliteClientConfig + readonly export: Effect.Effect + readonly loadExtension: (path: string) => Effect.Effect +} + +/** + * @category tags + * @since 1.0.0 + */ +export const SqliteClient: Context.Tag = Context.GenericTag( + "@effect/sql-sqlite-node/SqliteClient" +) + +/** + * @category models + * @since 1.0.0 + */ +export interface SqliteClientConfig { + readonly filename: string + readonly readonly?: boolean | undefined + readonly prepareCacheSize?: number | undefined + readonly prepareCacheTTL?: Duration.DurationInput | undefined + readonly disableWAL?: boolean | undefined + + readonly transformResultNames?: ((str: string) => string) | undefined + readonly transformQueryNames?: ((str: string) => string) | undefined +} + +interface SqliteConnection extends Connection { + readonly export: Effect.Effect + readonly loadExtension: (path: string) => Effect.Effect +} + +/** + * @category constructor + * @since 1.0.0 + */ +export const make = ( + options: SqliteClientConfig +): Effect.Effect => + Effect.gen(function*(_) { + const compiler = makeCompiler(options.transformQueryNames) + const transformRows = Client.defaultTransforms( + options.transformResultNames! + ).array + + const makeConnection = Effect.gen(function*(_) { + const db = new Sqlite(options.filename, { + readonly: options.readonly ?? false + }) + yield* _(Effect.addFinalizer(() => Effect.sync(() => db.close()))) + + if (options.disableWAL !== true) { + db.pragma("journal_mode = WAL") + } + + const prepareCache = yield* _( + Cache.make({ + capacity: options.prepareCacheSize ?? 200, + timeToLive: options.prepareCacheTTL ?? Duration.minutes(10), + lookup: (sql: string) => + Effect.try({ + try: () => db.prepare(sql), + catch: (error) => new SqlError({ error }) + }) + }) + ) + + const run = ( + sql: string, + params: ReadonlyArray = [] + ) => + Effect.flatMap(prepareCache.get(sql), (statement) => + Effect.try({ + try: () => { + if (statement.reader) { + return statement.all(...params) as ReadonlyArray + } + statement.run(...params) + return [] + }, + catch: (error) => new SqlError({ error }) + })) + + const runTransform = options.transformResultNames + ? (sql: string, params?: ReadonlyArray) => Effect.map(run(sql, params), transformRows) + : run + + const runValues = ( + sql: string, + params: ReadonlyArray + ) => + Effect.acquireUseRelease( + prepareCache.get(sql).pipe(Effect.map((_) => _.raw(true))), + (statement) => + Effect.try({ + try: () => { + if (statement.reader) { + return statement.all(...params) as ReadonlyArray< + ReadonlyArray + > + } + statement.run(...params) + return [] + }, + catch: (error) => new SqlError({ error }) + }), + (statement) => Effect.sync(() => statement.raw(false)) + ) + + return identity({ + execute(sql, params) { + return runTransform(sql, params) + }, + executeValues(sql, params) { + return runValues(sql, params) + }, + executeWithoutTransform(sql, params) { + return run(sql, params) + }, + executeRaw(sql, params) { + return runTransform(sql, params) + }, + executeStream(_sql, _params) { + return Effect.dieMessage("executeStream not implemented") + }, + export: Effect.try({ + try: () => db.serialize(), + catch: (error) => new SqlError({ error }) + }), + loadExtension(path) { + return Effect.try({ + try: () => db.loadExtension(path), + catch: (error) => new SqlError({ error }) + }) + } + }) + }) + + const semaphore = yield* _(Effect.makeSemaphore(1)) + const connection = yield* _(makeConnection) + + const acquirer = semaphore.withPermits(1)(Effect.succeed(connection)) + const transactionAcquirer = Effect.uninterruptibleMask((restore) => + Effect.as( + Effect.zipRight( + restore(semaphore.take(1)), + Effect.tap( + Effect.scope, + (scope) => Scope.addFinalizer(scope, semaphore.release(1)) + ) + ), + connection + ) + ) + + return Object.assign( + Client.make({ + acquirer, + compiler, + transactionAcquirer + }), + { + config: options, + export: Effect.flatMap(acquirer, (_) => _.export), + loadExtension: (path: string) => Effect.flatMap(acquirer, (_) => _.loadExtension(path)) + } + ) + }) + +/** + * @category layers + * @since 1.0.0 + */ +export const layer = ( + config: Config.Config.Wrap +): Layer.Layer => + Layer.scoped( + SqliteClient, + Effect.flatMap(Config.unwrap(config), make) + ) + +const escape = Statement.defaultEscape("\"") + +/** + * @category compiler + * @since 1.0.0 + */ +export const makeCompiler = (transform?: (_: string) => string) => + Statement.makeCompiler({ + placeholder: (_) => `?`, + onIdentifier: transform ? (_) => escape(transform(_)) : escape, + onRecordUpdate: () => ["", []], + onCustom: () => ["", []] + }) diff --git a/packages/sql-sqlite-node/src/Migrator.ts b/packages/sql-sqlite-node/src/Migrator.ts new file mode 100644 index 0000000000..e5446ecbfe --- /dev/null +++ b/packages/sql-sqlite-node/src/Migrator.ts @@ -0,0 +1,89 @@ +/** + * @since 1.0.0 + */ +import * as Command from "@effect/platform/Command" +import type { CommandExecutor } from "@effect/platform/CommandExecutor" +import { FileSystem } from "@effect/platform/FileSystem" +import { Path } from "@effect/platform/Path" +import type { SqlError } from "@effect/sql/Error" +import * as Migrator from "@effect/sql/Migrator" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import * as Client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * from "@effect/sql/Migrator" + +/** + * @category constructor + * @since 1.0.0 + */ +export const run: ( + options: Migrator.MigratorOptions +) => Effect.Effect< + ReadonlyArray, + SqlError | Migrator.MigrationError, + Client.SqliteClient | R | FileSystem | Path | CommandExecutor +> = Migrator.make({ + getClient: Client.SqliteClient, + ensureTable(sql, table) { + return sql` + CREATE TABLE IF NOT EXISTS ${sql(table)} ( + migration_id integer PRIMARY KEY NOT NULL, + created_at datetime NOT NULL DEFAULT current_timestamp, + name VARCHAR(255) NOT NULL + ) + ` + }, + dumpSchema(sql, path, table) { + const dump = (args: Array) => + Effect.gen(function*(_) { + const dump = yield* _( + Command.make("sqlite3", sql.config.filename, ...args), + Command.string + ) + return dump.replace(/^create table sqlite_sequence\(.*$/im, "") + .replace(/\n{2,}/gm, "\n\n") + .trim() + }).pipe( + Effect.mapError((error) => new Migrator.MigrationError({ reason: "failed", message: error.message })) + ) + + const dumpSchema = dump([".schema"]) + + const dumpMigrations = dump([ + "--cmd", + `.mode insert ${table}`, + `select * from ${table}` + ]) + + const dumpAll = Effect.map( + Effect.all([dumpSchema, dumpMigrations], { concurrency: 2 }), + ([schema, migrations]) => schema + "\n\n" + migrations + ) + + const dumpFile = (file: string) => + Effect.gen(function*(_) { + const fs = yield* _(FileSystem) + const path = yield* _(Path) + const dump = yield* _(dumpAll) + yield* _(fs.makeDirectory(path.dirname(file), { recursive: true })) + yield* _(fs.writeFileString(file, dump)) + }).pipe( + Effect.mapError((error) => new Migrator.MigrationError({ reason: "failed", message: error.message })) + ) + + return dumpFile(path) + } +}) + +/** + * @category constructor + * @since 1.0.0 + */ +export const makeLayer = ( + options: Migrator.MigratorOptions +): Layer.Layer => + Layer.effectDiscard(run(options)) diff --git a/packages/sql-sqlite-node/src/index.ts b/packages/sql-sqlite-node/src/index.ts new file mode 100644 index 0000000000..72ae734924 --- /dev/null +++ b/packages/sql-sqlite-node/src/index.ts @@ -0,0 +1,33 @@ +/** + * @since 1.0.0 + */ + +/** + * @since 1.0.0 + */ +export * as client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * as error from "@effect/sql/Error" + +/** + * @since 1.0.0 + */ +export * as migrator from "./Migrator.js" + +/** + * @since 1.0.0 + */ +export * as resolver from "@effect/sql/Resolver" + +/** + * @since 1.0.0 + */ +export * as schema from "@effect/sql/Schema" + +/** + * @since 1.0.0 + */ +export * as statement from "@effect/sql/Statement" diff --git a/packages/sql-sqlite-node/test/Client.test.ts b/packages/sql-sqlite-node/test/Client.test.ts new file mode 100644 index 0000000000..5cfd224319 --- /dev/null +++ b/packages/sql-sqlite-node/test/Client.test.ts @@ -0,0 +1,30 @@ +import { FileSystem } from "@effect/platform" +import { NodeFileSystem } from "@effect/platform-node" +import * as Client from "@effect/sql-sqlite-node/Client" +import { assert, describe, it } from "@effect/vitest" +import { Effect } from "effect" + +const makeClient = Effect.gen(function*(_) { + const fs = yield* _(FileSystem.FileSystem) + const dir = yield* _(fs.makeTempDirectoryScoped()) + return yield* _(Client.make({ + filename: dir + "/test.db" + })) +}).pipe(Effect.provide(NodeFileSystem.layer)) + +describe("Client", () => { + it.effect("should work", () => + Effect.gen(function*(_) { + const sql = yield* _(makeClient) + yield* _(sql`CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)`) + yield* _(sql`INSERT INTO test (name) VALUES ('hello')`) + let rows = yield* _(sql`SELECT * FROM test`) + assert.deepStrictEqual(rows, [{ id: 1, name: "hello" }]) + yield* _(sql`INSERT INTO test (name) VALUES ('world')`, sql.withTransaction) + rows = yield* _(sql`SELECT * FROM test`) + assert.deepStrictEqual(rows, [ + { id: 1, name: "hello" }, + { id: 2, name: "world" } + ]) + }).pipe(Effect.scoped)) +}) diff --git a/packages/sql-sqlite-node/test/Resolver.test.ts b/packages/sql-sqlite-node/test/Resolver.test.ts new file mode 100644 index 0000000000..13cf76cdfe --- /dev/null +++ b/packages/sql-sqlite-node/test/Resolver.test.ts @@ -0,0 +1,179 @@ +import { FileSystem } from "@effect/platform" +import { NodeFileSystem } from "@effect/platform-node" +import * as Schema from "@effect/schema/Schema" +import * as Sql from "@effect/sql-sqlite-node" +import { assert, describe, it } from "@effect/vitest" +import { Effect, Option, ReadonlyArray } from "effect" + +const makeClient = Effect.gen(function*(_) { + const fs = yield* _(FileSystem.FileSystem) + const dir = yield* _(fs.makeTempDirectoryScoped()) + return yield* _(Sql.client.make({ + filename: dir + "/test.db" + })) +}).pipe(Effect.provide(NodeFileSystem.layer)) + +const seededClient = Effect.gen(function*(_) { + const sql = yield* _(makeClient) + yield* _(sql`CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)`) + yield* _( + Effect.forEach(ReadonlyArray.range(1, 100), (id) => sql`INSERT INTO test ${sql.insert({ id, name: `name${id}` })}`) + ) + return sql +}) + +describe("Resolver", () => { + describe("ordered", () => { + it.scoped("insert", () => + Effect.gen(function*(_) { + const batches: Array> = [] + const sql = yield* _(seededClient) + const Insert = yield* _(Sql.resolver.ordered("Insert", { + Request: Schema.String, + Result: Schema.Struct({ id: Schema.Number, name: Schema.String }), + execute: (names) => { + batches.push(names) + return sql`INSERT INTO test ${sql.insert(names.map((name) => ({ name })))} RETURNING *` + } + })) + assert.deepStrictEqual( + yield* _(Effect.all({ + one: Insert.execute("one"), + two: Insert.execute("two") + }, { batching: true })), + { + one: { id: 101, name: "one" }, + two: { id: 102, name: "two" } + } + ) + assert.deepStrictEqual(batches, [["one", "two"]]) + })) + + it.scoped("result length mismatch", () => + Effect.gen(function*(_) { + const batches: Array> = [] + const sql = yield* _(seededClient) + const Select = yield* _(Sql.resolver.ordered("Select", { + Request: Schema.Number, + Result: Schema.Struct({ id: Schema.Number, name: Schema.String }), + execute: (ids) => { + batches.push(ids) + return sql`SELECT * FROM test WHERE id IN ${sql.in(ids)}` + } + })) + const error = yield* _( + Effect.all([ + Select.execute(1), + Select.execute(2), + Select.execute(3), + Select.execute(101) + ], { batching: true }), + Effect.flip + ) + assert(error instanceof Sql.error.ResultLengthMismatch) + assert.strictEqual(error.actual, 3) + assert.strictEqual(error.expected, 4) + assert.deepStrictEqual(batches, [[1, 2, 3, 101]]) + })) + }) + + describe("grouped", () => { + it.scoped("find by name", () => + Effect.gen(function*(_) { + const sql = yield* _(seededClient) + const FindByName = yield* _(Sql.resolver.grouped("FindByName", { + Request: Schema.String, + RequestGroupKey: (name) => name, + Result: Schema.Struct({ id: Schema.Number, name: Schema.String }), + ResultGroupKey: (result) => result.name, + execute: (names) => sql`SELECT * FROM test WHERE name IN ${sql.in(names)}` + })) + yield* _(sql`INSERT INTO test ${sql.insert({ name: "name1" })}`) + assert.deepStrictEqual( + yield* _(Effect.all({ + one: FindByName.execute("name1"), + two: FindByName.execute("name2"), + three: FindByName.execute("name0") + }, { batching: true })), + { + one: [{ id: 1, name: "name1" }, { id: 101, name: "name1" }], + two: [{ id: 2, name: "name2" }], + three: [] + } + ) + })) + + it.scoped("using raw rows", () => + Effect.gen(function*(_) { + const sql = yield* _(seededClient) + const FindByName = yield* _(Sql.resolver.grouped("FindByName", { + Request: Schema.String, + RequestGroupKey: (name) => name, + Result: Schema.Struct({ id: Schema.Number, name: Schema.String }), + ResultGroupKey: (_, result: any) => result.name, + execute: (names) => sql`SELECT * FROM test WHERE name IN ${sql.in(names)}` + })) + yield* _(sql`INSERT INTO test ${sql.insert({ name: "name1" })}`) + assert.deepStrictEqual( + yield* _(Effect.all({ + one: FindByName.execute("name1"), + two: FindByName.execute("name2"), + three: FindByName.execute("name0") + }, { batching: true })), + { + one: [{ id: 1, name: "name1" }, { id: 101, name: "name1" }], + two: [{ id: 2, name: "name2" }], + three: [] + } + ) + })) + }) + + describe("findById", () => { + it.scoped("find by id", () => + Effect.gen(function*(_) { + const sql = yield* _(seededClient) + const FindById = yield* _(Sql.resolver.findById("FindById", { + Id: Schema.Number, + Result: Schema.Struct({ id: Schema.Number, name: Schema.String }), + ResultId: (result) => result.id, + execute: (ids) => sql`SELECT * FROM test WHERE id IN ${sql.in(ids)}` + })) + assert.deepStrictEqual( + yield* _(Effect.all({ + one: FindById.execute(1), + two: FindById.execute(2), + three: FindById.execute(101) + }, { batching: true })), + { + one: Option.some({ id: 1, name: "name1" }), + two: Option.some({ id: 2, name: "name2" }), + three: Option.none() + } + ) + })) + + it.scoped("using raw rows", () => + Effect.gen(function*(_) { + const sql = yield* _(seededClient) + const FindById = yield* _(Sql.resolver.findById("FindById", { + Id: Schema.Number, + Result: Schema.Struct({ id: Schema.Number, name: Schema.String }), + ResultId: (_, result: any) => result.id, + execute: (ids) => sql`SELECT * FROM test WHERE id IN ${sql.in(ids)}` + })) + assert.deepStrictEqual( + yield* _(Effect.all({ + one: FindById.execute(1), + two: FindById.execute(2), + three: FindById.execute(101) + }, { batching: true })), + { + one: Option.some({ id: 1, name: "name1" }), + two: Option.some({ id: 2, name: "name2" }), + three: Option.none() + } + ) + })) + }) +}) diff --git a/packages/sql-sqlite-node/tsconfig.build.json b/packages/sql-sqlite-node/tsconfig.build.json new file mode 100644 index 0000000000..808406fd4c --- /dev/null +++ b/packages/sql-sqlite-node/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.src.json", + "references": [{ "path": "../effect" }, { "path": "../sql" }], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/build.tsbuildinfo", + "outDir": "build/esm", + "declarationDir": "build/dts", + "stripInternal": true + } +} diff --git a/packages/sql-sqlite-node/tsconfig.examples.json b/packages/sql-sqlite-node/tsconfig.examples.json new file mode 100644 index 0000000000..119ff192eb --- /dev/null +++ b/packages/sql-sqlite-node/tsconfig.examples.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["examples"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../experimental" }, + { "path": "../sql" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/examples.tsbuildinfo", + "rootDir": "examples", + "noEmit": true + } +} diff --git a/packages/sql-sqlite-node/tsconfig.json b/packages/sql-sqlite-node/tsconfig.json new file mode 100644 index 0000000000..3edbf6b8a5 --- /dev/null +++ b/packages/sql-sqlite-node/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "include": [], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "tsconfig.test.json" }, + { "path": "tsconfig.examples.json" } + ] +} diff --git a/packages/sql-sqlite-node/tsconfig.src.json b/packages/sql-sqlite-node/tsconfig.src.json new file mode 100644 index 0000000000..7f6843ca24 --- /dev/null +++ b/packages/sql-sqlite-node/tsconfig.src.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src", "../sql-sqlite-wasm/src/sqlite-wasm.d.ts"], + "references": [{ "path": "../effect" }, { "path": "../sql" }], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/src.tsbuildinfo", + "rootDir": "src", + "outDir": "build/src" + } +} diff --git a/packages/sql-sqlite-node/tsconfig.test.json b/packages/sql-sqlite-node/tsconfig.test.json new file mode 100644 index 0000000000..70103fe42a --- /dev/null +++ b/packages/sql-sqlite-node/tsconfig.test.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["test"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../platform-node" }, + { "path": "../sql" }, + { "path": "../vitest" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/test.tsbuildinfo", + "rootDir": "test", + "noEmit": true + } +} diff --git a/packages/sql-sqlite-node/vitest.config.ts b/packages/sql-sqlite-node/vitest.config.ts new file mode 100644 index 0000000000..0411095f25 --- /dev/null +++ b/packages/sql-sqlite-node/vitest.config.ts @@ -0,0 +1,6 @@ +import { mergeConfig, type UserConfigExport } from "vitest/config" +import shared from "../../vitest.shared.js" + +const config: UserConfigExport = {} + +export default mergeConfig(shared, config) diff --git a/packages/sql-sqlite-react-native/LICENSE b/packages/sql-sqlite-react-native/LICENSE new file mode 100644 index 0000000000..7f6fe480f7 --- /dev/null +++ b/packages/sql-sqlite-react-native/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023-present The Contributors + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/packages/sql-sqlite-react-native/README.md b/packages/sql-sqlite-react-native/README.md new file mode 100644 index 0000000000..ad1a80d9c3 --- /dev/null +++ b/packages/sql-sqlite-react-native/README.md @@ -0,0 +1,5 @@ +# Effect SQL - SQLite + +An @effect/sql implementation using the `react-native-quick-sqlite` library. + +See here for more information: https://github.com/Effect-TS/effect/tree/main/packages/sql diff --git a/packages/sql-sqlite-react-native/docgen.json b/packages/sql-sqlite-react-native/docgen.json new file mode 100644 index 0000000000..f980a32f52 --- /dev/null +++ b/packages/sql-sqlite-react-native/docgen.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../node_modules/@effect/docgen/schema.json", + "exclude": [ + "src/internal/**/*.ts" + ] +} diff --git a/packages/sql-sqlite-react-native/package.json b/packages/sql-sqlite-react-native/package.json new file mode 100644 index 0000000000..f2b18c4558 --- /dev/null +++ b/packages/sql-sqlite-react-native/package.json @@ -0,0 +1,51 @@ +{ + "name": "@effect/sql-sqlite-react-native", + "version": "0.0.0", + "type": "module", + "license": "MIT", + "description": "A SQLite toolkit for Effect", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/effect-ts/effect.git", + "directory": "packages/sql-sqlite-react-native" + }, + "bugs": { + "url": "https://github.com/effect-ts/effect/issues" + }, + "tags": [ + "typescript", + "sql", + "database" + ], + "keywords": [ + "typescript", + "sql", + "database" + ], + "publishConfig": { + "access": "public", + "directory": "dist", + "provenance": true + }, + "scripts": { + "build": "pnpm build-esm && pnpm build-cjs && pnpm build-annotate && build-utils pack-v2", + "build-esm": "tsc -b tsconfig.build.json", + "build-cjs": "babel build/esm --plugins @babel/transform-export-namespace-from --plugins @babel/transform-modules-commonjs --out-dir build/cjs --source-maps", + "build-annotate": "babel build --plugins annotate-pure-calls --out-dir build --source-maps", + "check": "tsc -b tsconfig.json", + "test": "vitest", + "coverage": "vitest --coverage" + }, + "devDependencies": { + "@effect/sql": "workspace:^", + "effect": "workspace:^" + }, + "peerDependencies": { + "@effect/sql": "workspace:^", + "effect": "workspace:^" + }, + "dependencies": { + "react-native-quick-sqlite": "^8.0.6" + } +} diff --git a/packages/sql-sqlite-react-native/src/Client.ts b/packages/sql-sqlite-react-native/src/Client.ts new file mode 100644 index 0000000000..9654e43143 --- /dev/null +++ b/packages/sql-sqlite-react-native/src/Client.ts @@ -0,0 +1,183 @@ +/** + * @since 1.0.0 + */ +import * as Client from "@effect/sql/Client" +import type { Connection } from "@effect/sql/Connection" +import { SqlError } from "@effect/sql/Error" +import * as Statement from "@effect/sql/Statement" +import * as Config from "effect/Config" +import type { ConfigError } from "effect/ConfigError" +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import * as FiberRef from "effect/FiberRef" +import { identity } from "effect/Function" +import { globalValue } from "effect/GlobalValue" +import * as Layer from "effect/Layer" +import * as Scope from "effect/Scope" +import * as Sqlite from "react-native-quick-sqlite" + +/** + * @category models + * @since 1.0.0 + */ +export interface SqliteClient extends Client.Client { + readonly config: SqliteClientConfig +} + +/** + * @category tags + * @since 1.0.0 + */ +export const SqliteClient: Context.Tag = Context.GenericTag( + "@effect/sql-sqlite-react-native/SqliteClient" +) + +/** + * @category models + * @since 1.0.0 + */ +export interface SqliteClientConfig { + readonly filename: string + readonly location?: string | undefined + readonly transformResultNames?: ((str: string) => string) | undefined + readonly transformQueryNames?: ((str: string) => string) | undefined +} + +/** + * @category fiber refs + * @since 1.0.0 + */ +export const asyncQuery: FiberRef.FiberRef = globalValue( + "@effect/sql-sqlite-react-native/Client/asyncQuery", + () => FiberRef.unsafeMake(false) +) + +/** + * @category fiber refs + * @since 1.0.0 + */ +export const withAsyncQuery = (effect: Effect.Effect) => Effect.locally(effect, asyncQuery, true) + +/** + * @category constructor + * @since 1.0.0 + */ +export const make = ( + options: SqliteClientConfig +): Effect.Effect => + Effect.gen(function*(_) { + const compiler = makeCompiler(options.transformQueryNames) + const transformRows = Client.defaultTransforms( + options.transformResultNames! + ).array + + const handleError = (error: any) => new SqlError({ error }) + + const makeConnection = Effect.gen(function*(_) { + const db = Sqlite.open({ + name: options.filename, + location: options.location! + }) + yield* _(Effect.addFinalizer(() => Effect.sync(() => db.close()))) + + const run = ( + sql: string, + params: ReadonlyArray = [] + ) => + Effect.withFiberRuntime, SqlError>((fiber) => { + if (fiber.getFiberRef(asyncQuery)) { + return Effect.map( + Effect.tryPromise({ + try: () => db.executeAsync(sql, params as Array), + catch: handleError + }), + (result) => result.rows?._array ?? [] + ) + } + return Effect.try({ + try: () => db.execute(sql, params as Array).rows?._array ?? [], + catch: handleError + }) + }) + + const runTransform = options.transformResultNames + ? (sql: string, params?: ReadonlyArray) => Effect.map(run(sql, params), transformRows) + : run + + return identity({ + execute(sql, params) { + return runTransform(sql, params) + }, + executeValues(sql, params) { + return Effect.map(run(sql, params), (results) => { + if (results.length === 0) { + return [] + } + const columns = Object.keys(results[0]) + return results.map((row) => columns.map((column) => row[column])) + }) + }, + executeWithoutTransform(sql, params) { + return run(sql, params) + }, + executeRaw(sql, params) { + return runTransform(sql, params) + }, + executeStream() { + return Effect.dieMessage("executeStream not implemented") + } + }) + }) + + const semaphore = yield* _(Effect.makeSemaphore(1)) + const connection = yield* _(makeConnection) + + const acquirer = semaphore.withPermits(1)(Effect.succeed(connection)) + const transactionAcquirer = Effect.uninterruptibleMask((restore) => + Effect.as( + Effect.zipRight( + restore(semaphore.take(1)), + Effect.tap( + Effect.scope, + (scope) => Scope.addFinalizer(scope, semaphore.release(1)) + ) + ), + connection + ) + ) + + return Object.assign( + Client.make({ + acquirer, + compiler, + transactionAcquirer + }), + { config: options } + ) + }) + +/** + * @category layers + * @since 1.0.0 + */ +export const layer = ( + config: Config.Config.Wrap +): Layer.Layer => + Layer.scoped( + SqliteClient, + Effect.flatMap(Config.unwrap(config), make) + ) + +const escape = Statement.defaultEscape("\"") + +/** + * @category compiler + * @since 1.0.0 + */ +export const makeCompiler = (transform?: (_: string) => string) => + Statement.makeCompiler({ + placeholder: (_) => `?`, + onIdentifier: transform ? (_) => escape(transform(_)) : escape, + onRecordUpdate: () => ["", []], + onCustom: () => ["", []] + }) diff --git a/packages/sql-sqlite-react-native/src/Migrator.ts b/packages/sql-sqlite-react-native/src/Migrator.ts new file mode 100644 index 0000000000..1e7bfdf58d --- /dev/null +++ b/packages/sql-sqlite-react-native/src/Migrator.ts @@ -0,0 +1,47 @@ +/** + * @since 1.0.0 + */ +import type { SqlError } from "@effect/sql/Error" +import * as Migrator from "@effect/sql/Migrator" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import * as Client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * from "@effect/sql/Migrator" + +/** + * @category constructor + * @since 1.0.0 + */ +export const run: ( + options: Migrator.MigratorOptions +) => Effect.Effect< + ReadonlyArray, + SqlError | Migrator.MigrationError, + Client.SqliteClient | R +> = Migrator.make({ + getClient: Client.SqliteClient, + ensureTable(sql, table) { + return sql` + CREATE TABLE IF NOT EXISTS ${sql(table)} ( + migration_id integer PRIMARY KEY NOT NULL, + created_at datetime NOT NULL DEFAULT current_timestamp, + name VARCHAR(255) NOT NULL + ) + ` + }, + dumpSchema(_sql, _path, _table) { + return Effect.unit + } +}) + +/** + * @category constructor + * @since 1.0.0 + */ +export const makeLayer = ( + options: Migrator.MigratorOptions +): Layer.Layer => Layer.effectDiscard(run(options)) diff --git a/packages/sql-sqlite-react-native/src/index.ts b/packages/sql-sqlite-react-native/src/index.ts new file mode 100644 index 0000000000..72ae734924 --- /dev/null +++ b/packages/sql-sqlite-react-native/src/index.ts @@ -0,0 +1,33 @@ +/** + * @since 1.0.0 + */ + +/** + * @since 1.0.0 + */ +export * as client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * as error from "@effect/sql/Error" + +/** + * @since 1.0.0 + */ +export * as migrator from "./Migrator.js" + +/** + * @since 1.0.0 + */ +export * as resolver from "@effect/sql/Resolver" + +/** + * @since 1.0.0 + */ +export * as schema from "@effect/sql/Schema" + +/** + * @since 1.0.0 + */ +export * as statement from "@effect/sql/Statement" diff --git a/packages/sql-sqlite-react-native/test/Client.test.ts b/packages/sql-sqlite-react-native/test/Client.test.ts new file mode 100644 index 0000000000..653e64614d --- /dev/null +++ b/packages/sql-sqlite-react-native/test/Client.test.ts @@ -0,0 +1,6 @@ +import { describe, it } from "@effect/vitest" +import { Effect } from "effect" + +describe("Client", () => { + it.effect("should work", () => Effect.unit) +}) diff --git a/packages/sql-sqlite-react-native/tsconfig.build.json b/packages/sql-sqlite-react-native/tsconfig.build.json new file mode 100644 index 0000000000..808406fd4c --- /dev/null +++ b/packages/sql-sqlite-react-native/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.src.json", + "references": [{ "path": "../effect" }, { "path": "../sql" }], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/build.tsbuildinfo", + "outDir": "build/esm", + "declarationDir": "build/dts", + "stripInternal": true + } +} diff --git a/packages/sql-sqlite-react-native/tsconfig.examples.json b/packages/sql-sqlite-react-native/tsconfig.examples.json new file mode 100644 index 0000000000..119ff192eb --- /dev/null +++ b/packages/sql-sqlite-react-native/tsconfig.examples.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["examples"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../experimental" }, + { "path": "../sql" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/examples.tsbuildinfo", + "rootDir": "examples", + "noEmit": true + } +} diff --git a/packages/sql-sqlite-react-native/tsconfig.json b/packages/sql-sqlite-react-native/tsconfig.json new file mode 100644 index 0000000000..3edbf6b8a5 --- /dev/null +++ b/packages/sql-sqlite-react-native/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "include": [], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "tsconfig.test.json" }, + { "path": "tsconfig.examples.json" } + ] +} diff --git a/packages/sql-sqlite-react-native/tsconfig.src.json b/packages/sql-sqlite-react-native/tsconfig.src.json new file mode 100644 index 0000000000..424a843861 --- /dev/null +++ b/packages/sql-sqlite-react-native/tsconfig.src.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src"], + "references": [{ "path": "../effect" }, { "path": "../sql" }], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/src.tsbuildinfo", + "rootDir": "src", + "outDir": "build/src" + } +} diff --git a/packages/sql-sqlite-react-native/tsconfig.test.json b/packages/sql-sqlite-react-native/tsconfig.test.json new file mode 100644 index 0000000000..9d0a40abed --- /dev/null +++ b/packages/sql-sqlite-react-native/tsconfig.test.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["test"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../sql" }, + { "path": "../vitest" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/test.tsbuildinfo", + "rootDir": "test", + "noEmit": true + } +} diff --git a/packages/sql-sqlite-react-native/vitest.config.ts b/packages/sql-sqlite-react-native/vitest.config.ts new file mode 100644 index 0000000000..0411095f25 --- /dev/null +++ b/packages/sql-sqlite-react-native/vitest.config.ts @@ -0,0 +1,6 @@ +import { mergeConfig, type UserConfigExport } from "vitest/config" +import shared from "../../vitest.shared.js" + +const config: UserConfigExport = {} + +export default mergeConfig(shared, config) diff --git a/packages/sql-sqlite-wasm/LICENSE b/packages/sql-sqlite-wasm/LICENSE new file mode 100644 index 0000000000..7f6fe480f7 --- /dev/null +++ b/packages/sql-sqlite-wasm/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023-present The Contributors + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/packages/sql-sqlite-wasm/README.md b/packages/sql-sqlite-wasm/README.md new file mode 100644 index 0000000000..4a8a6c9f97 --- /dev/null +++ b/packages/sql-sqlite-wasm/README.md @@ -0,0 +1,5 @@ +# Effect SQL - SQLite + +An @effect/sql implementation using the `@sqlite.org/sqlite-wasm` library. + +See here for more information: https://github.com/Effect-TS/effect/tree/main/packages/sql diff --git a/packages/sql-sqlite-wasm/docgen.json b/packages/sql-sqlite-wasm/docgen.json new file mode 100644 index 0000000000..f980a32f52 --- /dev/null +++ b/packages/sql-sqlite-wasm/docgen.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../node_modules/@effect/docgen/schema.json", + "exclude": [ + "src/internal/**/*.ts" + ] +} diff --git a/packages/sql-sqlite-wasm/package.json b/packages/sql-sqlite-wasm/package.json new file mode 100644 index 0000000000..b2b5dfdea3 --- /dev/null +++ b/packages/sql-sqlite-wasm/package.json @@ -0,0 +1,51 @@ +{ + "name": "@effect/sql-sqlite-wasm", + "version": "0.0.0", + "type": "module", + "license": "MIT", + "description": "A SQLite toolkit for Effect", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/effect-ts/effect.git", + "directory": "packages/sql-sqlite-wasm" + }, + "bugs": { + "url": "https://github.com/effect-ts/effect/issues" + }, + "tags": [ + "typescript", + "sql", + "database" + ], + "keywords": [ + "typescript", + "sql", + "database" + ], + "publishConfig": { + "access": "public", + "directory": "dist", + "provenance": true + }, + "scripts": { + "build": "pnpm build-esm && pnpm build-cjs && pnpm build-annotate && build-utils pack-v2", + "build-esm": "tsc -b tsconfig.build.json", + "build-cjs": "babel build/esm --plugins @babel/transform-export-namespace-from --plugins @babel/transform-modules-commonjs --out-dir build/cjs --source-maps", + "build-annotate": "babel build --plugins annotate-pure-calls --out-dir build --source-maps", + "check": "tsc -b tsconfig.json", + "test": "vitest", + "coverage": "vitest --coverage" + }, + "devDependencies": { + "@effect/sql": "workspace:^", + "effect": "workspace:^" + }, + "peerDependencies": { + "@effect/sql": "workspace:^", + "effect": "workspace:^" + }, + "dependencies": { + "@sqlite.org/sqlite-wasm": "3.45.2-build1" + } +} diff --git a/packages/sql-sqlite-wasm/src/Client.ts b/packages/sql-sqlite-wasm/src/Client.ts new file mode 100644 index 0000000000..92927457a7 --- /dev/null +++ b/packages/sql-sqlite-wasm/src/Client.ts @@ -0,0 +1,191 @@ +/** + * @since 1.0.0 + */ +import * as Client from "@effect/sql/Client" +import type { Connection } from "@effect/sql/Connection" +import { SqlError } from "@effect/sql/Error" +import * as Statement from "@effect/sql/Statement" +import type { DB, OpenMode, RowMode } from "@sqlite.org/sqlite-wasm" +import sqliteInit from "@sqlite.org/sqlite-wasm" +import * as Config from "effect/Config" +import type { ConfigError } from "effect/ConfigError" +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import { identity } from "effect/Function" +import * as Layer from "effect/Layer" +import * as Scope from "effect/Scope" + +/** + * @category models + * @since 1.0.0 + */ +export interface SqliteClient extends Client.Client { + readonly config: SqliteClientConfig + readonly export: Effect.Effect +} + +/** + * @category tags + * @since 1.0.0 + */ +export const SqliteClient: Context.Tag = Context.GenericTag( + "@effect/sql-sqlite-wasm/SqliteClient" +) + +/** + * @category models + * @since 1.0.0 + */ +export type SqliteClientConfig = + | { + readonly mode?: "vfs" + readonly dbName?: string + readonly openMode?: OpenMode + readonly transformResultNames?: (str: string) => string + readonly transformQueryNames?: (str: string) => string + } + | { + readonly mode: "opfs" + readonly dbName: string + readonly openMode?: OpenMode + readonly transformResultNames?: (str: string) => string + readonly transformQueryNames?: (str: string) => string + } + +interface SqliteConnection extends Connection { + readonly export: Effect.Effect +} + +const initEffect = Effect.runSync( + Effect.cached(Effect.promise(() => sqliteInit())) +) + +/** + * @category constructor + * @since 1.0.0 + */ +export const make = ( + options: SqliteClientConfig +): Effect.Effect => + Effect.gen(function*(_) { + const compiler = makeCompiler(options.transformQueryNames) + const transformRows = Client.defaultTransforms( + options.transformResultNames! + ).array + + const makeConnection = Effect.gen(function*(_) { + const sqlite3 = yield* _(initEffect) + + let db: DB + if (options.mode === "opfs") { + if (!sqlite3.oo1.OpfsDb) { + yield* _(Effect.dieMessage("opfs mode not available")) + } + db = new sqlite3.oo1.OpfsDb!(options.dbName, options.openMode ?? "c") + } else { + db = new sqlite3.oo1.DB(options.dbName, options.openMode) + } + + yield* _(Effect.addFinalizer(() => Effect.sync(() => db.close()))) + + const run = ( + sql: string, + params: ReadonlyArray = [], + rowMode: RowMode = "object" + ) => + Effect.try({ + try: () => { + const results: Array = [] + db.exec({ + sql, + bind: params.length ? params : undefined, + rowMode, + resultRows: results + }) + return results + }, + catch: (error) => new SqlError({ error }) + }) + + const runTransform = options.transformResultNames + ? (sql: string, params?: ReadonlyArray) => Effect.map(run(sql, params), transformRows) + : run + + return identity({ + execute(sql, params) { + return runTransform(sql, params) + }, + executeValues(sql, params) { + return run(sql, params, "array") + }, + executeWithoutTransform(sql, params) { + return run(sql, params) + }, + executeRaw(sql, params) { + return runTransform(sql, params) + }, + executeStream() { + return Effect.dieMessage("executeStream not implemented") + }, + export: Effect.try({ + try: () => sqlite3.capi.sqlite3_js_db_export(db.pointer), + catch: (error) => new SqlError({ error }) + }) + }) + }) + + const semaphore = yield* _(Effect.makeSemaphore(1)) + const connection = yield* _(makeConnection) + + const acquirer = semaphore.withPermits(1)(Effect.succeed(connection)) + const transactionAcquirer = Effect.uninterruptibleMask((restore) => + Effect.as( + Effect.zipRight( + restore(semaphore.take(1)), + Effect.tap( + Effect.scope, + (scope) => Scope.addFinalizer(scope, semaphore.release(1)) + ) + ), + connection + ) + ) + + return Object.assign( + Client.make({ + acquirer, + compiler, + transactionAcquirer + }), + { + config: options, + export: Effect.flatMap(acquirer, (_) => _.export) + } + ) + }) + +/** + * @category layers + * @since 1.0.0 + */ +export const layer = ( + config: Config.Config.Wrap +): Layer.Layer => + Layer.scoped( + SqliteClient, + Effect.flatMap(Config.unwrap(config), make) + ) + +const escape = Statement.defaultEscape("\"") + +/** + * @category compiler + * @since 1.0.0 + */ +export const makeCompiler = (transform?: (_: string) => string) => + Statement.makeCompiler({ + placeholder: (_) => `?`, + onIdentifier: transform ? (_) => escape(transform(_)) : escape, + onRecordUpdate: () => ["", []], + onCustom: () => ["", []] + }) diff --git a/packages/sql-sqlite-wasm/src/Migrator.ts b/packages/sql-sqlite-wasm/src/Migrator.ts new file mode 100644 index 0000000000..1e7bfdf58d --- /dev/null +++ b/packages/sql-sqlite-wasm/src/Migrator.ts @@ -0,0 +1,47 @@ +/** + * @since 1.0.0 + */ +import type { SqlError } from "@effect/sql/Error" +import * as Migrator from "@effect/sql/Migrator" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import * as Client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * from "@effect/sql/Migrator" + +/** + * @category constructor + * @since 1.0.0 + */ +export const run: ( + options: Migrator.MigratorOptions +) => Effect.Effect< + ReadonlyArray, + SqlError | Migrator.MigrationError, + Client.SqliteClient | R +> = Migrator.make({ + getClient: Client.SqliteClient, + ensureTable(sql, table) { + return sql` + CREATE TABLE IF NOT EXISTS ${sql(table)} ( + migration_id integer PRIMARY KEY NOT NULL, + created_at datetime NOT NULL DEFAULT current_timestamp, + name VARCHAR(255) NOT NULL + ) + ` + }, + dumpSchema(_sql, _path, _table) { + return Effect.unit + } +}) + +/** + * @category constructor + * @since 1.0.0 + */ +export const makeLayer = ( + options: Migrator.MigratorOptions +): Layer.Layer => Layer.effectDiscard(run(options)) diff --git a/packages/sql-sqlite-wasm/src/index.ts b/packages/sql-sqlite-wasm/src/index.ts new file mode 100644 index 0000000000..72ae734924 --- /dev/null +++ b/packages/sql-sqlite-wasm/src/index.ts @@ -0,0 +1,33 @@ +/** + * @since 1.0.0 + */ + +/** + * @since 1.0.0 + */ +export * as client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * as error from "@effect/sql/Error" + +/** + * @since 1.0.0 + */ +export * as migrator from "./Migrator.js" + +/** + * @since 1.0.0 + */ +export * as resolver from "@effect/sql/Resolver" + +/** + * @since 1.0.0 + */ +export * as schema from "@effect/sql/Schema" + +/** + * @since 1.0.0 + */ +export * as statement from "@effect/sql/Statement" diff --git a/packages/sql-sqlite-wasm/src/sqlite-wasm.d.ts b/packages/sql-sqlite-wasm/src/sqlite-wasm.d.ts new file mode 100644 index 0000000000..3ebdfb9620 --- /dev/null +++ b/packages/sql-sqlite-wasm/src/sqlite-wasm.d.ts @@ -0,0 +1,45 @@ +/** + * @since 1.0.0 + */ + +declare module "@sqlite.org/sqlite-wasm" { + export type OpenMode = "c" | "ct" | "w" | "wt" | "r" | "rt" + export type RowMode = "object" | "array" | "stmt" + + export interface SqliteHandle { + readonly _: unique symbol + } + + export class DB { + constructor(dbName?: string, mode?: OpenMode) + + readonly pointer: SqliteHandle + + exec(options: { + sql: string + bind?: ReadonlyArray | undefined + rowMode?: RowMode | undefined + resultRows?: Array | undefined + }) + + close(): void + } + class OpfsDb extends DB {} + + interface OO1 { + readonly DB: typeof DB + readonly OpfsDb?: typeof OpfsDb + } + + interface CApi { + readonly sqlite3_js_db_export: (db: SqliteHandle) => Uint8Array + } + + interface SqliteWasm { + readonly oo1: OO1 + readonly capi: CApi + } + + const init: () => Promise + export default init +} diff --git a/packages/sql-sqlite-wasm/test/Client.test.ts b/packages/sql-sqlite-wasm/test/Client.test.ts new file mode 100644 index 0000000000..653e64614d --- /dev/null +++ b/packages/sql-sqlite-wasm/test/Client.test.ts @@ -0,0 +1,6 @@ +import { describe, it } from "@effect/vitest" +import { Effect } from "effect" + +describe("Client", () => { + it.effect("should work", () => Effect.unit) +}) diff --git a/packages/sql-sqlite-wasm/tsconfig.build.json b/packages/sql-sqlite-wasm/tsconfig.build.json new file mode 100644 index 0000000000..808406fd4c --- /dev/null +++ b/packages/sql-sqlite-wasm/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.src.json", + "references": [{ "path": "../effect" }, { "path": "../sql" }], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/build.tsbuildinfo", + "outDir": "build/esm", + "declarationDir": "build/dts", + "stripInternal": true + } +} diff --git a/packages/sql-sqlite-wasm/tsconfig.examples.json b/packages/sql-sqlite-wasm/tsconfig.examples.json new file mode 100644 index 0000000000..119ff192eb --- /dev/null +++ b/packages/sql-sqlite-wasm/tsconfig.examples.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["examples"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../experimental" }, + { "path": "../sql" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/examples.tsbuildinfo", + "rootDir": "examples", + "noEmit": true + } +} diff --git a/packages/sql-sqlite-wasm/tsconfig.json b/packages/sql-sqlite-wasm/tsconfig.json new file mode 100644 index 0000000000..3edbf6b8a5 --- /dev/null +++ b/packages/sql-sqlite-wasm/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "include": [], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "tsconfig.test.json" }, + { "path": "tsconfig.examples.json" } + ] +} diff --git a/packages/sql-sqlite-wasm/tsconfig.src.json b/packages/sql-sqlite-wasm/tsconfig.src.json new file mode 100644 index 0000000000..424a843861 --- /dev/null +++ b/packages/sql-sqlite-wasm/tsconfig.src.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src"], + "references": [{ "path": "../effect" }, { "path": "../sql" }], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/src.tsbuildinfo", + "rootDir": "src", + "outDir": "build/src" + } +} diff --git a/packages/sql-sqlite-wasm/tsconfig.test.json b/packages/sql-sqlite-wasm/tsconfig.test.json new file mode 100644 index 0000000000..70103fe42a --- /dev/null +++ b/packages/sql-sqlite-wasm/tsconfig.test.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["test"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../platform-node" }, + { "path": "../sql" }, + { "path": "../vitest" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/test.tsbuildinfo", + "rootDir": "test", + "noEmit": true + } +} diff --git a/packages/sql-sqlite-wasm/vitest.config.ts b/packages/sql-sqlite-wasm/vitest.config.ts new file mode 100644 index 0000000000..0411095f25 --- /dev/null +++ b/packages/sql-sqlite-wasm/vitest.config.ts @@ -0,0 +1,6 @@ +import { mergeConfig, type UserConfigExport } from "vitest/config" +import shared from "../../vitest.shared.js" + +const config: UserConfigExport = {} + +export default mergeConfig(shared, config) diff --git a/packages/sql/LICENSE b/packages/sql/LICENSE new file mode 100644 index 0000000000..7f6fe480f7 --- /dev/null +++ b/packages/sql/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023-present The Contributors + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/packages/sql/README.md b/packages/sql/README.md new file mode 100644 index 0000000000..0820f3be38 --- /dev/null +++ b/packages/sql/README.md @@ -0,0 +1,271 @@ +# Effect SQL + +A SQL toolkit for Effect. + +## Basic example + +```ts +import { Config, Effect, Struct, pipe } from "effect"; +import * as Sql from "@effect/sql-pg"; + +const SqlLive = Sql.client.layer({ + database: Config.succeed("effect_pg_dev"), +}); + +const program = Effect.gen(function* (_) { + const sql = yield* _(Sql.client.PgClient); + + const people = yield* _( + sql<{ + readonly id: number; + readonly name: string; + }>`SELECT id, name FROM people` + ); + + yield* _(Effect.log(`Got ${people.length} results!`)); +}); + +pipe(program, Effect.provide(SqlLive), Effect.runPromise); +``` + +## INSERT resolver + +```ts +import { Effect, pipe } from "effect"; +import * as Schema from "@effect/schema/Schema"; +import * as Sql from "@effect/sql-pg"; + +class Person extends Schema.Class("Person")({ + id: Schema.number, + name: Schema.string, + createdAt: Schema.DateFromSelf, + updatedAt: Schema.DateFromSelf, +}) {} + +const InsertPersonSchema = Schema.struct( + Struct.omit(Person.fields, "id", "createdAt", "updatedAt") +); + +export const makePersonService = Effect.gen(function* (_) { + const sql = yield* _(Sql.client.PgClient); + + const InsertPerson = yield* _( + Sql.resolver.ordered("InsertPerson", { + Request: InsertPersonSchema, + Result: Person, + execute: (requests) => + sql` + INSERT INTO people + ${sql.insert(requests)} + RETURNING people.* + `, + }) + ); + const insert = InsertPerson.execute; + + return { insert }; +}); +``` + +## SELECT resolver + +```ts +import { Effect, pipe } from "effect"; +import * as Schema from "@effect/schema/Schema"; +import * as Sql from "@effect/sql-pg"; + +class Person extends Schema.Class("Person")({ + id: Schema.number, + name: Schema.string, + createdAt: Schema.DateFromSelf, + updatedAt: Schema.DateFromSelf, +}) {} + +export const makePersonService = Effect.gen(function* (_) { + const sql = yield* _(Sql.client.PgClient); + + const GetById = yield* _( + Sql.resolver.findById("GetPersonById", { + Id: Schema.number, + Result: Person, + ResultId: (_) => _.id, + execute: (ids) => sql`SELECT * FROM people WHERE id IN ${sql(ids)}`, + }) + ); + + const getById = (id: number) => + Effect.withRequestCaching("on")(GetById.execute(id)); + + return { getById }; +}); +``` + +## Building queries + +### Safe interpolation + +```ts +import { Effect } from "effect"; +import * as Sql from "@effect/sql-pg"; + +export const make = (limit: number) => + Effect.gen(function* (_) { + const sql = yield* _(Sql.client.PgClient); + + const statement = sql`SELECT * FROM people LIMIT ${limit}`; + // e.g. SELECT * FROM people LIMIT ? + }); +``` + +### Identifiers + +```ts +import { Effect } from "effect"; +import * as Sql from "@effect/sql-pg"; + +const table = "people"; + +export const make = (limit: number) => + Effect.gen(function* (_) { + const sql = yield* _(Sql.client.PgClient); + + const statement = sql`SELECT * FROM ${sql(table)} LIMIT ${limit}`; + // e.g. SELECT * FROM "people" LIMIT ? + }); +``` + +### Unsafe interpolation + +```ts +import * as Effect from "effect/Effect"; +import * as Sql from "@effect/sql-pg"; + +type OrderBy = "id" | "created_at" | "updated_at"; +type SortOrder = "ASC" | "DESC"; + +export const make = (orderBy: OrderBy, sortOrder: SortOrder) => + Effect.gen(function* (_) { + const sql = yield* _(Sql.client.PgClient); + + const statement = sql`SELECT * FROM people ORDER BY ${sql(orderBy)} ${sql.unsafe(sortOrder)}`; + // e.g. SELECT * FROM people ORDER BY `id` ASC + }); +``` + +### Where clause combinators + +#### AND + +```ts +import { Effect } from "effect"; +import * as Sql from "@effect/sql-pg"; + +export const make = (names: string[], cursor: string) => + Effect.gen(function* (_) { + const sql = yield* _(Sql.client.PgClient); + + const statement = sql`SELECT * FROM people WHERE ${sql.and([ + sql`name IN ${sql.in(names)}`, + sql`created_at < ${cursor}`, + ])}`; + // SELECT * FROM people WHERE (name IN (?,?,?) AND created_at < ?) + }); +``` + +#### OR + +```ts +import { Effect } from "effect"; +import * as Sql from "@effect/sql-pg"; + +export const make = (names: string[], cursor: Date) => + Effect.gen(function* (_) { + const sql = yield* _(Sql.client.PgClient); + + const statement = sql`SELECT * FROM people WHERE ${sql.or([ + sql`name IN ${sql.in(names)}`, + sql`created_at < ${cursor}`, + ])}`; + // SELECT * FROM people WHERE (name IN (?,?,?) OR created_at < ?) + }); +``` + +#### Mixed + +```ts +import { Effect } from "effect"; +import * as Sql from "@effect/sql-pg"; + +export const make = (names: string[], afterCursor: Date, beforeCursor: Date) => + Effect.gen(function* (_) { + const sql = yield* _(Sql.client.PgClient); + + const statement = sql`SELECT * FROM people WHERE ${sql.or([ + sql`name IN ${sql.in(names)}`, + sql.and([`created_at > ${afterCursor}`, `created_at < ${beforeCursor}`]), + ])}`; + // SELECT * FROM people WHERE (name IN (?,?,?) OR (created_at > ? AND created_at < ?)) + }); +``` + +## Migrations + +A `Migrator` module is provided, for running migrations. + +Migrations are forward-only, and are written in Typescript as Effect's. + +Here is an example migration: + +```ts +// src/migrations/0001_add_users.ts + +import { Effect } from "effect"; +import * as Sql from "@effect/sql-pg"; + +export default Effect.flatMap( + Sql.client.PgClient, + (sql) => sql` + CREATE TABLE users ( + id serial PRIMARY KEY, + name varchar(255) NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + updated_at TIMESTAMP NOT NULL DEFAULT NOW() + ) + ` +); +``` + +To run your migrations: + +```ts +// src/main.ts + +import { Config, Effect, Layer, pipe } from "effect"; +import { NodeContext, NodeRuntime } from "@effect/platform-node"; +import * as Sql from "@effect/sql-pg"; +import { fileURLToPath } from "node:url"; + +const program = Effect.gen(function* (_) { + // ... +}); + +const SqlLive = Sql.client.layer({ + database: Config.succeed("example_database"), +}); + +const MigratorLive = Sql.migrator + .layer({ + loader: Sql.migrator.fromFileSystem( + fileURLToPath(new URL("migrations", import.meta.url)) + ), + // Where to put the `_schema.sql` file + schemaDirectory: "src/migrations", + }) + .pipe(Layer.provide(SqlLive)); + +const EnvLive = Layer.mergeAll(SqlLive, MigratorLive).pipe( + Layer.provide(NodeContext.layer) +); + +pipe(program, Effect.provide(EnvLive), NodeRuntime.runMain); +``` diff --git a/packages/sql/docgen.json b/packages/sql/docgen.json new file mode 100644 index 0000000000..f980a32f52 --- /dev/null +++ b/packages/sql/docgen.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../node_modules/@effect/docgen/schema.json", + "exclude": [ + "src/internal/**/*.ts" + ] +} diff --git a/packages/sql/package.json b/packages/sql/package.json new file mode 100644 index 0000000000..b6601a3008 --- /dev/null +++ b/packages/sql/package.json @@ -0,0 +1,53 @@ +{ + "name": "@effect/sql", + "version": "0.0.0", + "type": "module", + "license": "MIT", + "description": "A SQL toolkit for Effect", + "homepage": "https://effect.website", + "repository": { + "type": "git", + "url": "https://github.com/effect-ts/effect.git", + "directory": "packages/sql" + }, + "bugs": { + "url": "https://github.com/effect-ts/effect/issues" + }, + "tags": [ + "typescript", + "sql", + "database" + ], + "keywords": [ + "typescript", + "algebraic-data-types", + "functional-programming", + "sql", + "database" + ], + "publishConfig": { + "access": "public", + "directory": "dist", + "provenance": true + }, + "scripts": { + "codegen": "build-utils prepare-v2", + "build": "pnpm codegen && pnpm build-esm && pnpm build-cjs && pnpm build-annotate && build-utils pack-v2", + "build-esm": "tsc -b tsconfig.build.json", + "build-cjs": "babel build/esm --plugins @babel/transform-export-namespace-from --plugins @babel/transform-modules-commonjs --out-dir build/cjs --source-maps", + "build-annotate": "babel build --plugins annotate-pure-calls --out-dir build --source-maps", + "check": "tsc -b tsconfig.json", + "test": "vitest", + "coverage": "vitest --coverage" + }, + "devDependencies": { + "@effect/platform": "workspace:^", + "@effect/schema": "workspace:^", + "effect": "workspace:^" + }, + "peerDependencies": { + "@effect/platform": "workspace:^", + "@effect/schema": "workspace:^", + "effect": "workspace:^" + } +} diff --git a/packages/sql/src/Client.ts b/packages/sql/src/Client.ts new file mode 100644 index 0000000000..4b0cbc0124 --- /dev/null +++ b/packages/sql/src/Client.ts @@ -0,0 +1,104 @@ +/** + * @since 1.0.0 + */ +import type { Tag } from "effect/Context" +import type { Effect } from "effect/Effect" +import type { Scope } from "effect/Scope" +import type { Connection } from "./Connection.js" +import type { SqlError } from "./Error.js" +import * as internal from "./internal/client.js" +import type { Compiler, Constructor } from "./Statement.js" + +/** + * @category type ids + * @since 1.0.0 + */ +export const TypeId: unique symbol = internal.TypeId + +/** + * @category type ids + * @since 1.0.0 + */ +export type TypeId = typeof TypeId + +/** + * @category models + * @since 1.0.0 + */ +export interface Client extends Constructor { + readonly [TypeId]: TypeId + + /** + * Copy of the client for safeql etc. + */ + readonly safe: this + + readonly reserve: Effect + + /** + * With the given effect, ensure all sql queries are run in a transaction. + */ + readonly withTransaction: ( + self: Effect + ) => Effect +} + +/** + * @category models + * @since 1.0.0 + */ +export namespace Client { + /** + * @category models + * @since 1.0.0 + */ + export interface MakeOptions { + readonly acquirer: Connection.Acquirer + readonly compiler: Compiler + readonly transactionAcquirer: Connection.Acquirer + readonly beginTransaction?: string + readonly rollback?: string + readonly commit?: string + readonly savepoint?: (name: string) => string + readonly rollbackSavepoint?: (name: string) => string + } +} + +/** + * @category constructors + * @since 1.0.0 + */ +export const make: ({ + acquirer, + beginTransaction, + commit, + rollback, + rollbackSavepoint, + savepoint, + transactionAcquirer +}: Client.MakeOptions) => Client = internal.make + +/** + * @since 1.0.0 + */ +export const defaultTransforms: ( + transformer: (str: string) => string, + nested?: boolean +) => { + readonly value: (value: any) => any + readonly object: (obj: Record) => any + readonly array: (rows: ReadonlyArray) => ReadonlyArray +} = internal.defaultTransforms + +/** + * @since 1.0.0 + */ +export interface TransactionConnection { + readonly _: unique symbol +} + +/** + * @since 1.0.0 + */ +export const TransactionConnection: Tag = + internal.TransactionConnection diff --git a/packages/sql/src/Connection.ts b/packages/sql/src/Connection.ts new file mode 100644 index 0000000000..1f3ac6639a --- /dev/null +++ b/packages/sql/src/Connection.ts @@ -0,0 +1,63 @@ +/** + * @since 1.0.0 + */ +import * as Context from "effect/Context" +import type { Effect } from "effect/Effect" +import type { Scope } from "effect/Scope" +import type { Stream } from "effect/Stream" +import type { SqlError } from "./Error.js" +import type { Primitive } from "./Statement.js" + +/** + * @category model + * @since 1.0.0 + */ +export interface Connection { + readonly execute: ( + sql: string, + params: ReadonlyArray + ) => Effect, SqlError> + + readonly executeStream: ( + sql: string, + params: ReadonlyArray + ) => Stream + + readonly executeWithoutTransform: ( + sql: string, + params: ReadonlyArray + ) => Effect, SqlError> + + readonly executeValues: ( + sql: string, + params: ReadonlyArray + ) => Effect>, SqlError> + + readonly executeRaw: ( + sql: string, + params?: ReadonlyArray | undefined + ) => Effect, SqlError> +} + +/** + * @since 1.0.0 + */ +export namespace Connection { + /** + * @category model + * @since 1.0.0 + */ + export type Acquirer = Effect +} + +/** + * @category tag + * @since 1.0.0 + */ +export const Connection = Context.GenericTag("@services/Connection") + +/** + * @category model + * @since 1.0.0 + */ +export type Row = { readonly [column: string]: Primitive } diff --git a/packages/sql/src/Error.ts b/packages/sql/src/Error.ts new file mode 100644 index 0000000000..641915c6da --- /dev/null +++ b/packages/sql/src/Error.ts @@ -0,0 +1,44 @@ +/** + * @since 1.0.0 + */ +import { RefailError, TypeIdError } from "@effect/platform/Error" +import * as Predicate from "effect/Predicate" + +/** + * @since 1.0.0 + */ +export const SqlErrorTypeId = Symbol.for("@effect/sql/Error") + +/** + * @since 1.0.0 + */ +export type SqlErrorTypeId = typeof SqlErrorTypeId + +/** + * @since 1.0.0 + */ +export class SqlError extends RefailError(SqlErrorTypeId, "SqlError")<{}> { + get code() { + if (Predicate.hasProperty(this.error, "code")) { + return this.error.code + } + return undefined + } + + get message() { + const code = this.code + return code ? `${code}: ${super.message}` : super.message + } +} + +/** + * @since 1.0.0 + */ +export class ResultLengthMismatch extends TypeIdError(SqlErrorTypeId, "ResultLengthMismatch")<{ + readonly expected: number + readonly actual: number +}> { + get message() { + return `Expected ${this.expected} results but got ${this.actual}` + } +} diff --git a/packages/sql/src/Migrator.ts b/packages/sql/src/Migrator.ts new file mode 100644 index 0000000000..12952168c7 --- /dev/null +++ b/packages/sql/src/Migrator.ts @@ -0,0 +1,344 @@ +/** + * @since 1.0.0 + */ +import { FileSystem } from "@effect/platform/FileSystem" +import * as Data from "effect/Data" +import * as Effect from "effect/Effect" +import { pipe } from "effect/Function" +import * as Option from "effect/Option" +import * as Order from "effect/Order" +import * as ReadonlyArray from "effect/ReadonlyArray" +import type { Client } from "./Client.js" +import type { SqlError } from "./Error.js" + +/** + * @category model + * @since 1.0.0 + */ +export interface MigratorOptions { + readonly loader: Loader + readonly schemaDirectory?: string + readonly table?: string +} + +/** + * @category model + * @since 1.0.0 + */ +export type Loader = Effect.Effect< + ReadonlyArray, + MigrationError, + R +> + +/** + * @category model + * @since 1.0.0 + */ +export type ResolvedMigration = readonly [ + id: number, + name: string, + load: Effect.Effect +] + +/** + * @category model + * @since 1.0.0 + */ +export interface Migration { + readonly id: number + readonly name: string + readonly createdAt: Date +} + +/** + * @category errors + * @since 1.0.0 + */ +export class MigrationError extends Data.TaggedError("MigrationError")<{ + readonly _tag: "MigrationError" + readonly reason: + | "bad-state" + | "import-error" + | "failed" + | "duplicates" + | "locked" + readonly message: string +}> {} + +/** + * @category constructor + * @since 1.0.0 + */ +export const make = ({ + dumpSchema, + ensureTable, + getClient, + lockTable = () => Effect.unit +}: { + getClient: Effect.Effect + dumpSchema: ( + sql: R, + path: string, + migrationsTable: string + ) => Effect.Effect + ensureTable: (sql: R, table: string) => Effect.Effect + lockTable?: (sql: R, table: string) => Effect.Effect +}) => +({ + loader, + schemaDirectory, + table = "effect_sql_migrations" +}: MigratorOptions): Effect.Effect< + ReadonlyArray, + MigrationError | SqlError, + R | RD | RE | RL | R2 +> => + Effect.gen(function*(_) { + const sql = yield* _(getClient) + const ensureMigrationsTable = ensureTable(sql, table) + + const insertMigrations = ( + rows: ReadonlyArray<[id: number, name: string]> + ) => + sql`INSERT INTO ${sql(table)} ${ + sql.insert( + rows.map(([migration_id, name]) => ({ migration_id, name })) + ) + }`.withoutTransform + + const latestMigration = Effect.map( + sql<{ migration_id: number; name: string; created_at: Date }>`SELECT migration_id, name, created_at FROM ${ + sql(table) + } ORDER BY migration_id DESC`.withoutTransform, + (_) => + Option.map( + Option.fromNullable(_[0] as any), + ({ created_at, migration_id, name }): Migration => ({ + id: migration_id, + name, + createdAt: created_at + }) + ) + ) + + const loadMigration = ([id, name, load]: ResolvedMigration) => + Effect.catchAllDefect(load, (_) => + Effect.fail( + new MigrationError({ + reason: "import-error", + message: `Could not import migration "${id}_${name}"\n\n${_}` + }) + )).pipe( + Effect.flatMap((_) => + Effect.isEffect(_) + ? Effect.succeed(_) + : _.default + ? Effect.succeed(_.default?.default ?? _.default) + : Effect.fail( + new MigrationError({ + reason: "import-error", + message: `Default export not found for migration "${id}_${name}"` + }) + ) + ), + Effect.filterOrFail( + (_): _ is Effect.Effect => Effect.isEffect(_), + () => + new MigrationError({ + reason: "import-error", + message: `Default export was not an Effect for migration "${id}_${name}"` + }) + ) + ) + + const runMigration = ( + id: number, + name: string, + effect: Effect.Effect + ) => + Effect.orDieWith(effect, (_) => + new MigrationError({ + reason: "failed", + message: `Migration "${id}_${name}" failed: ${JSON.stringify(_)}` + })) + + // === run + + const run = Effect.gen(function*(_) { + yield* _(lockTable(sql, table)) + + const [latestMigrationId, current] = yield* _( + Effect.all([ + Effect.map( + latestMigration, + Option.match({ + onNone: () => 0, + onSome: (_) => _.id + }) + ), + loader + ]) + ) + + if (new Set(current.map(([id]) => id)).size !== current.length) { + yield* _( + new MigrationError({ + reason: "duplicates", + message: "Found duplicate migration id's" + }) + ) + } + + const required: Array = [] + + for (const resolved of current) { + const [currentId, currentName] = resolved + if (currentId <= latestMigrationId) { + continue + } + + required.push([ + currentId, + currentName, + yield* _(loadMigration(resolved)) + ]) + } + + if (required.length > 0) { + yield* _( + insertMigrations(required.map(([id, name]) => [id, name])), + Effect.mapError((_) => + new MigrationError({ + reason: "locked", + message: "Migrations already running" + }) + ) + ) + } + + yield* _( + Effect.forEach( + required, + ([id, name, effect]) => + Effect.logDebug(`Running migration`).pipe( + Effect.zipRight(runMigration(id, name, effect)), + Effect.annotateLogs("migration_id", String(id)), + Effect.annotateLogs("migration_name", name) + ), + { discard: true } + ) + ) + + yield* _( + latestMigration, + Effect.flatMap( + Option.match({ + onNone: () => Effect.logDebug(`Migrations complete`), + onSome: (_) => + Effect.logDebug(`Migrations complete`).pipe( + Effect.annotateLogs("latest_migration_id", _.id.toString()), + Effect.annotateLogs("latest_migration_name", _.name) + ) + }) + ) + ) + + return required.map(([id, name]) => [id, name] as const) + }) + + yield* _(ensureMigrationsTable) + + const completed = yield* _( + sql.withTransaction(run), + Effect.catchTag("MigrationError", (_) => + _.reason === "locked" + ? Effect.as(Effect.logDebug(_.message), []) + : Effect.fail(_)) + ) + + if (schemaDirectory && completed.length > 0) { + yield* _( + dumpSchema(sql, `${schemaDirectory}/_schema.sql`, table), + Effect.catchAllCause((cause) => Effect.logInfo("Could not dump schema", cause)) + ) + } + + return completed + }) + +const migrationOrder = Order.make(([a], [b]) => Order.number(a, b)) + +/** + * @since 1.0.0 + * @category loaders + */ +export const fromGlob = ( + migrations: Record Promise> +): Loader => + pipe( + Object.keys(migrations), + ReadonlyArray.filterMap((_) => Option.fromNullable(_.match(/^(?:.*\/)?(\d+)_([^.]+)\.(js|ts)$/))), + ReadonlyArray.map( + ([key, id, name]): ResolvedMigration => [ + Number(id), + name, + Effect.promise(() => migrations[key]()) + ] + ), + ReadonlyArray.sort(migrationOrder), + Effect.succeed + ) + +/** + * @since 1.0.0 + * @category loaders + */ +export const fromBabelGlob = (migrations: Record): Loader => + pipe( + Object.keys(migrations), + ReadonlyArray.filterMap((_) => Option.fromNullable(_.match(/^_(\d+)_([^.]+?)(Js|Ts)?$/))), + ReadonlyArray.map( + ([key, id, name]): ResolvedMigration => [ + Number(id), + name, + Effect.succeed(migrations[key]) + ] + ), + ReadonlyArray.sort(migrationOrder), + Effect.succeed + ) + +/** + * @since 1.0.0 + * @category loaders + */ +export const fromFileSystem = (directory: string): Loader => + FileSystem.pipe( + Effect.flatMap((FS) => FS.readDirectory(directory)), + Effect.mapError((error) => new MigrationError({ reason: "failed", message: error.message })), + Effect.map((files): ReadonlyArray => + files + .map((file) => Option.fromNullable(file.match(/^(?:.*\/)?(\d+)_([^.]+)\.(js|ts)$/))) + .flatMap( + Option.match({ + onNone: () => [], + onSome: ([basename, id, name]): ReadonlyArray => + [ + [ + Number(id), + name, + Effect.promise( + () => + import( + /* @vite-ignore */ + `${directory}/${basename}` + ) + ) + ] + ] as const + }) + ) + .sort(([a], [b]) => a - b) + ) + ) diff --git a/packages/sql/src/Resolver.ts b/packages/sql/src/Resolver.ts new file mode 100644 index 0000000000..02e2a21a85 --- /dev/null +++ b/packages/sql/src/Resolver.ts @@ -0,0 +1,463 @@ +/** + * @since 1.0.0 + */ +import type { ParseError } from "@effect/schema/ParseResult" +import * as Schema from "@effect/schema/Schema" +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import * as Equal from "effect/Equal" +import * as Exit from "effect/Exit" +import * as FiberRef from "effect/FiberRef" +import * as Hash from "effect/Hash" +import * as Option from "effect/Option" +import * as Request from "effect/Request" +import * as RequestResolver from "effect/RequestResolver" +import * as Tracer from "effect/Tracer" +import type * as Types from "effect/Types" +import { ResultLengthMismatch } from "./Error.js" +import * as internalClient from "./internal/client.js" + +/** + * @since 1.0.0 + * @category requests + */ +export interface SqlRequest extends Request.Request { + readonly _tag: T + readonly spanLink: Tracer.SpanLink + readonly input: unknown +} + +const SqlRequestProto = { + ...Request.Class.prototype, + [Equal.symbol]( + this: SqlRequest, + that: SqlRequest + ): boolean { + return this._tag === that._tag && Equal.equals(this.input, that.input) + }, + [Hash.symbol](this: SqlRequest): number { + return Hash.cached(this, Hash.combine(Hash.hash(this.input))(Hash.string(this._tag))) + } +} + +const makeRequest = ( + tag: T, + input: I, + span: Tracer.Span +): SqlRequest => { + const self = Object.create(SqlRequestProto) as Types.Mutable> + self._tag = tag + self.spanLink = { + _tag: "SpanLink", + span, + attributes: {} + } + self.input = input + return self +} + +const partitionRequests = (requests: ReadonlyArray>) => { + const len = requests.length + const inputs: Array = new Array(len) + const spanLinks: Array = new Array(len) + + for (let i = 0; i < len; i++) { + const request = requests[i] + inputs[i] = request.input + spanLinks[i] = request.spanLink + } + + return [inputs, spanLinks] as const +} + +const partitionRequestsById = () => (requests: ReadonlyArray>) => { + const len = requests.length + const inputs: Array = new Array(len) + const spanLinks: Array = new Array(len) + const byIdMap = new Map>() + + for (let i = 0; i < len; i++) { + const request = requests[i] + inputs[i] = request.input + spanLinks[i] = request.spanLink + byIdMap.set(request.input as I, request) + } + + return [inputs, spanLinks, byIdMap] as const +} + +/** + * @since 1.0.0 + * @category resolvers + */ +export interface SqlResolver + extends RequestResolver.RequestResolver> +{ + readonly execute: (input: I) => Effect.Effect + readonly makeExecute: ( + resolver: RequestResolver.RequestResolver> + ) => (input: I) => Effect.Effect + readonly cachePopulate: ( + id: I, + result: A + ) => Effect.Effect + readonly cacheInvalidate: (id: I) => Effect.Effect + readonly request: (input: I) => Effect.Effect, ParseError, R> +} + +const makeResolver = ( + self: RequestResolver.RequestResolver>, + tag: T, + Request: Schema.Schema, + withContext?: boolean +): Effect.Effect, never, R> => { + function make(context: Context.Context | undefined) { + const encode = Schema.encode(Request) + function makeExecute(self: RequestResolver.RequestResolver>) { + return function(input: I) { + return Effect.useSpan( + `sql.Resolver.execute ${tag}`, + (span) => + Effect.withFiberRuntime((fiber) => { + span.attribute("request.input", input) + const currentContext = fiber.getFiberRef(FiberRef.currentContext) + const connection = currentContext.unsafeMap.get( + internalClient.TransactionConnection.key + ) + let toProvide: Context.Context | undefined = context + if (connection !== undefined) { + if (toProvide === undefined) { + toProvide = Context.make( + internalClient.TransactionConnection, + connection + ) as Context.Context + } else { + toProvide = Context.add( + toProvide, + internalClient.TransactionConnection, + connection + ) + } + } + const resolver = toProvide === undefined + ? self + : RequestResolver.provideContext(self, toProvide) + return Effect.flatMap( + encode(input), + (input) => Effect.request(makeRequest(tag, input, span), resolver) + ) + }) + ) + } + } + return Object.assign(self, { + request(input: I) { + return Effect.withFiberRuntime, ParseError, RI>( + (fiber) => { + const span = fiber + .getFiberRef(FiberRef.currentContext) + .unsafeMap.get(Tracer.ParentSpan.key) + return Effect.map(encode(input), (input) => makeRequest(tag, input, span)) + } + ) + }, + cachePopulate(input: I, value: A) { + return Effect.flatMap( + encode(input), + (input) => Effect.cacheRequestResult(makeRequest(tag, input, null as any), Exit.succeed(value)) + ) + }, + cacheInvalidate(input: I) { + return Effect.withFiberRuntime((fiber) => { + const cache = fiber.getFiberRef(FiberRef.currentRequestCache) + return Effect.flatMap(encode(input), (input) => cache.invalidate(makeRequest(tag, input, null as any))) + }) + }, + makeExecute, + execute: makeExecute(self) + }) + } + + return withContext === true ? Effect.map(Effect.context(), make) : Effect.succeed(make(undefined)) +} + +/** + * Create a resolver for a sql query with a request schema and a result schema. + * + * The request schema is used to validate the input of the query. + * The result schema is used to validate the output of the query. + * + * Results are mapped to the requests in order, so the length of the results must match the length of the requests. + * + * @since 1.0.0 + * @category resolvers + */ +export const ordered = ( + tag: T, + options: + | { + readonly Request: Schema.Schema + readonly Result: Schema.Schema + readonly execute: ( + requests: Array> + ) => Effect.Effect, E> + readonly withContext?: false + } + | { + readonly Request: Schema.Schema + readonly Result: Schema.Schema + readonly execute: ( + requests: Array> + ) => Effect.Effect, E, R> + readonly withContext: true + } +): Effect.Effect< + SqlResolver, + never, + RA | R +> => { + const decodeResults = Schema.decodeUnknown(Schema.Array(options.Result)) + const resolver = RequestResolver.makeBatched( + (requests: Array>) => { + const [inputs, spanLinks] = partitionRequests(requests) + return options.execute(inputs as any).pipe( + Effect.filterOrFail( + (results) => results.length === inputs.length, + ({ length }) => + new ResultLengthMismatch({ + expected: inputs.length, + actual: length + }) + ), + Effect.flatMap(decodeResults), + Effect.flatMap( + Effect.forEach((result, i) => Request.succeed(requests[i], result), { + discard: true + }) + ), + Effect.catchAllCause((cause) => + Effect.forEach( + requests, + (request) => Request.failCause(request, cause), + { discard: true } + ) + ), + Effect.withSpan(`sql.Resolver.batch ${tag}`, { + links: spanLinks, + attributes: { "request.count": inputs.length } + }) + ) as Effect.Effect + } + ).identified(`@effect/sql/Resolver.ordered/${tag}`) + return makeResolver(resolver, tag, options.Request, options.withContext) +} + +/** + * Create a resolver the can return multiple results for a single request. + * + * Results are grouped by a common key extracted from the request and result. + * + * @since 1.0.0 + * @category resolvers + */ +export const grouped = ( + tag: T, + options: + | { + readonly Request: Schema.Schema + readonly RequestGroupKey: (request: NoInfer) => K + readonly Result: Schema.Schema + readonly ResultGroupKey: (result: NoInfer, row: NoInfer) => K + readonly execute: ( + requests: Array> + ) => Effect.Effect, E> + readonly withContext?: false + } + | { + readonly Request: Schema.Schema + readonly RequestGroupKey: (request: NoInfer) => K + readonly Result: Schema.Schema + readonly ResultGroupKey: (result: NoInfer, row: NoInfer) => K + readonly execute: ( + requests: Array> + ) => Effect.Effect, E, R> + readonly withContext: true + } +): Effect.Effect, E, RI>, never, RA | R> => { + const decodeResults = Schema.decodeUnknown(Schema.Array(options.Result)) + const resolver = RequestResolver.makeBatched( + (requests: Array, E>>) => { + const [inputs, spanLinks] = partitionRequests(requests) + const resultMap = new Map>() + return options.execute(inputs as any).pipe( + Effect.bindTo("rawResults"), + Effect.bind("results", ({ rawResults }) => decodeResults(rawResults)), + Effect.tap(({ rawResults, results }) => { + for (let i = 0, len = results.length; i < len; i++) { + const result = results[i] + const key = options.ResultGroupKey(result, rawResults[i]) + const group = resultMap.get(key) + if (group === undefined) { + resultMap.set(key, [result]) + } else { + group.push(result) + } + } + + return Effect.forEach( + requests, + (request) => { + const key = options.RequestGroupKey(request.input as II) + return Request.succeed(request, resultMap.get(key) ?? []) + }, + { discard: true } + ) + }), + Effect.catchAllCause((cause) => + Effect.forEach( + requests, + (request) => Request.failCause(request, cause), + { discard: true } + ) + ), + Effect.withSpan(`sql.Resolver.batch ${tag}`, { + links: spanLinks, + attributes: { "request.count": inputs.length } + }) + ) as Effect.Effect + } + ).identified(`@effect/sql/Resolver.grouped/${tag}`) + return makeResolver(resolver, tag, options.Request, options.withContext) +} + +/** + * Create a resolver that resolves results by id. + * + * @since 1.0.0 + * @category resolvers + */ +export const findById = ( + tag: T, + options: + | { + readonly Id: Schema.Schema + readonly Result: Schema.Schema + readonly ResultId: (result: NoInfer, row: NoInfer) => II + readonly execute: ( + requests: Array> + ) => Effect.Effect, E> + readonly withContext?: false + } + | { + readonly Id: Schema.Schema + readonly Result: Schema.Schema + readonly ResultId: (result: NoInfer, row: NoInfer) => II + readonly execute: ( + requests: Array> + ) => Effect.Effect, E, R> + readonly withContext: true + } +): Effect.Effect, E, RI>, never, RA | R> => { + const decodeResults = Schema.decodeUnknown(Schema.Array(options.Result)) + const resolver = RequestResolver.makeBatched( + (requests: Array, E>>) => { + const [inputs, spanLinks, idMap] = partitionRequestsById()(requests) + return options.execute(inputs as any).pipe( + Effect.bindTo("rawResults"), + Effect.bind("results", ({ rawResults }) => decodeResults(rawResults)), + Effect.flatMap(({ rawResults, results }) => + Effect.forEach( + results, + (result, i) => { + const id = options.ResultId(result, rawResults[i]) + const request = idMap.get(id) + if (request === undefined) { + return Effect.unit + } + idMap.delete(id) + return Request.succeed(request, Option.some(result)) + }, + { discard: true } + ) + ), + Effect.tap((_) => { + if (idMap.size === 0) { + return Effect.unit + } + return Effect.forEach( + idMap.values(), + (request) => Request.succeed(request, Option.none()), + { discard: true } + ) + }), + Effect.catchAllCause((cause) => + Effect.forEach( + requests, + (request) => Request.failCause(request, cause), + { discard: true } + ) + ), + Effect.withSpan(`sql.Resolver.batch ${tag}`, { + links: spanLinks, + attributes: { "request.count": inputs.length } + }) + ) as Effect.Effect + } + ).identified(`@effect/sql/Resolver.findById/${tag}`) + return makeResolver(resolver, tag, options.Id, options.withContext) +} +const void_ = ( + tag: T, + options: + | { + readonly Request: Schema.Schema + readonly execute: ( + requests: Array> + ) => Effect.Effect, E> + readonly withContext?: false + } + | { + readonly Request: Schema.Schema + readonly execute: ( + requests: Array> + ) => Effect.Effect, E, R> + readonly withContext: true + } +): Effect.Effect, never, R> => { + const resolver = RequestResolver.makeBatched( + (requests: Array>) => { + const [inputs, spanLinks] = partitionRequests(requests) + return options.execute(inputs as any).pipe( + Effect.andThen( + Effect.forEach( + requests, + (request) => Request.complete(request, Exit.unit), + { discard: true } + ) + ), + Effect.catchAllCause((cause) => + Effect.forEach( + requests, + (request) => Request.failCause(request, cause), + { discard: true } + ) + ), + Effect.withSpan(`sql.Resolver.batch ${tag}`, { + links: spanLinks, + attributes: { "request.count": inputs.length } + }) + ) as Effect.Effect + } + ).identified(`@effect/sql/Resolver.void/${tag}`) + return makeResolver(resolver, tag, options.Request, options.withContext) +} + +export { + /** + * Create a resolver that performs side effects. + * + * @since 1.0.0 + * @category resolvers + */ + void_ as void +} diff --git a/packages/sql/src/Schema.ts b/packages/sql/src/Schema.ts new file mode 100644 index 0000000000..000fe83a83 --- /dev/null +++ b/packages/sql/src/Schema.ts @@ -0,0 +1,73 @@ +/** + * @since 1.0.0 + */ +import type { ParseError } from "@effect/schema/ParseResult" +import * as Schema from "@effect/schema/Schema" +import * as Effect from "effect/Effect" +import type * as Option from "effect/Option" + +/** + * Run a sql query with a request schema and a result schema. + * + * @since 1.0.0 + * @category constructor + */ +export const findAll = ( + options: { + readonly Request: Schema.Schema + readonly Result: Schema.Schema + readonly execute: (request: II) => Effect.Effect, E, R> + } +) => { + const encodeRequest = Schema.encode(options.Request) + const decode = Schema.decodeUnknown(Schema.Array(options.Result)) + return (request: IA): Effect.Effect, E | ParseError, R | IR | AR> => + Effect.flatMap( + Effect.flatMap(encodeRequest(request), options.execute), + decode + ) +} + +const void_ = ( + options: { + readonly Request: Schema.Schema + readonly execute: (request: II) => Effect.Effect, E, R> + } +) => { + const encode = Schema.encode(options.Request) + return (request: IA): Effect.Effect => + Effect.asUnit( + Effect.flatMap(encode(request), options.execute) + ) +} +export { + /** + * Run a sql query with a request schema and discard the result. + * + * @since 1.0.0 + * @category constructor + */ + void_ as void +} + +/** + * Run a sql query with a request schema and a result schema and return the first result. + * + * @since 1.0.0 + * @category constructor + */ +export const findOne = ( + options: { + readonly Request: Schema.Schema + readonly Result: Schema.Schema + readonly execute: (request: II) => Effect.Effect, E, R> + } +) => { + const encodeRequest = Schema.encode(options.Request) + const decode = Schema.decodeUnknown(options.Result) + return (request: IA): Effect.Effect, E | ParseError, R | IR | AR> => + Effect.flatMap( + Effect.flatMap(encodeRequest(request), options.execute), + (arr) => Array.isArray(arr) && arr.length > 0 ? Effect.asSome(decode(arr[0])) : Effect.succeedNone + ) +} diff --git a/packages/sql/src/Statement.ts b/packages/sql/src/Statement.ts new file mode 100644 index 0000000000..38852aefd4 --- /dev/null +++ b/packages/sql/src/Statement.ts @@ -0,0 +1,428 @@ +/** + * @since 1.0.0 + */ +import type { Effect } from "effect/Effect" +import type * as FiberRef from "effect/FiberRef" +import type * as FiberRefs from "effect/FiberRefs" +import type * as Layer from "effect/Layer" +import type * as Option from "effect/Option" +import type { Pipeable } from "effect/Pipeable" +import type * as Stream from "effect/Stream" +import type * as Tracer from "effect/Tracer" +import type { Connection, Row } from "./Connection.js" +import type { SqlError } from "./Error.js" +import * as internal from "./internal/statement.js" + +/** + * @category type id + * @since 1.0.0 + */ +export const FragmentId: unique symbol = internal.FragmentId + +/** + * @category type id + * @since 1.0.0 + */ +export type FragmentId = typeof FragmentId + +/** + * @category model + * @since 1.0.0 + */ +export interface Fragment { + readonly [FragmentId]: (_: never) => FragmentId + readonly segments: ReadonlyArray +} + +/** + * @category model + * @since 1.0.0 + */ +export interface Statement extends Fragment, Effect, SqlError>, Pipeable { + readonly withoutTransform: Effect, SqlError> + readonly stream: Stream.Stream + readonly values: Effect>, SqlError> + readonly compile: () => readonly [ + sql: string, + params: ReadonlyArray + ] +} + +/** + * @category model + * @since 1.0.0 + */ +export declare namespace Statement { + /** + * @category model + * @since 1.0.0 + */ + export type Transformer = ( + self: Statement, + sql: Constructor, + context: FiberRefs.FiberRefs, + span: Tracer.Span + ) => Statement +} + +/** + * @category transformer + * @since 1.0.0 + */ +export const currentTransformer: FiberRef.FiberRef> = internal.currentTransformer + +/** + * @category transformer + * @since 1.0.0 + */ +export const withTransformer: { + ( + f: Statement.Transformer + ): (effect: Effect) => Effect + ( + effect: Effect, + f: Statement.Transformer + ): Effect +} = internal.withTransformer + +/** + * @category transformer + * @since 1.0.0 + */ +export const withTransformerDisabled: (effect: Effect) => Effect = + internal.withTransformerDisabled + +/** + * @category transformer + * @since 1.0.0 + */ +export const setTransformer: (f: Statement.Transformer) => Layer.Layer = internal.setTransformer + +/** + * @category guard + * @since 1.0.0 + */ +export const isFragment: (u: unknown) => u is Fragment = internal.isFragment + +/** + * @category guard + * @since 1.0.0 + */ +export const isCustom: >( + kind: A["kind"] +) => (u: unknown) => u is A = internal.isCustom + +/** + * @category model + * @since 1.0.0 + */ +export type Segment = + | Literal + | Identifier + | Parameter + | ArrayHelper + | RecordInsertHelper + | RecordUpdateHelper + | RecordUpdateHelperSingle + | Custom + +/** + * @category model + * @since 1.0.0 + */ +export interface Literal { + readonly _tag: "Literal" + readonly value: string + readonly params?: ReadonlyArray | undefined +} + +/** + * @category model + * @since 1.0.0 + */ +export interface Identifier { + readonly _tag: "Identifier" + readonly value: string +} + +/** + * @category model + * @since 1.0.0 + */ +export interface Parameter { + readonly _tag: "Parameter" + readonly value: Primitive +} + +/** + * @category model + * @since 1.0.0 + */ +export interface ArrayHelper { + readonly _tag: "ArrayHelper" + readonly value: ReadonlyArray +} + +/** + * @category model + * @since 1.0.0 + */ +export interface RecordInsertHelper { + readonly _tag: "RecordInsertHelper" + readonly value: ReadonlyArray> +} + +/** + * @category model + * @since 1.0.0 + */ +export interface RecordUpdateHelper { + readonly _tag: "RecordUpdateHelper" + readonly value: ReadonlyArray> + readonly alias: string +} + +/** + * @category model + * @since 1.0.0 + */ +export interface RecordUpdateHelperSingle { + readonly _tag: "RecordUpdateHelperSingle" + readonly value: Record + readonly omit: ReadonlyArray +} + +/** + * @category model + * @since 1.0.0 + */ +export interface Custom< + T extends string = string, + A = void, + B = void, + C = void +> { + readonly _tag: "Custom" + readonly kind: T + readonly i0: A + readonly i1: B + readonly i2: C +} + +/** + * @category constructor + * @since 1.0.0 + */ +export const custom: >( + kind: C["kind"] +) => (i0: C["i0"], i1: C["i1"], i2: C["i2"]) => Fragment = internal.custom + +/** + * @category model + * @since 1.0.0 + */ +export type Primitive = + | string + | number + | bigint + | boolean + | Date + | null + | Int8Array + | Uint8Array + +/** + * @category model + * @since 1.0.0 + */ +export type PrimitiveKind = + | "string" + | "number" + | "bigint" + | "boolean" + | "Date" + | "null" + | "Int8Array" + | "Uint8Array" + +/** + * @category model + * @since 1.0.0 + */ +export type Helper = + | ArrayHelper + | RecordInsertHelper + | RecordUpdateHelper + | RecordUpdateHelperSingle + | Identifier + | Custom + +/** + * @category model + * @since 1.0.0 + */ +export type Argument = Primitive | Helper | Fragment + +/** + * @category model + * @since 1.0.0 + */ +export interface Constructor { + ( + strings: TemplateStringsArray, + ...args: Array + ): Statement + + (value: string): Identifier + + /** + * Create unsafe SQL query + */ + readonly unsafe: ( + sql: string, + params?: ReadonlyArray | undefined + ) => Statement + + readonly literal: (sql: string) => Fragment + + readonly in: (value: ReadonlyArray) => ArrayHelper + + readonly insert: { + ( + value: ReadonlyArray> + ): RecordInsertHelper + (value: Record): RecordInsertHelper + } + + readonly update: >( + value: A, + omit?: ReadonlyArray + ) => RecordUpdateHelperSingle + + readonly updateValues: ( + value: ReadonlyArray>, + alias: string + ) => RecordUpdateHelper + + /** + * Create an `AND` chain for a where clause + */ + readonly and: (clauses: ReadonlyArray) => Fragment + + /** + * Create an `OR` chain for a where clause + */ + readonly or: (clauses: ReadonlyArray) => Fragment + + /** + * Create comma seperated values, with an optional prefix + * + * Useful for `ORDER BY` and `GROUP BY` clauses + */ + readonly csv: { + (values: ReadonlyArray): Fragment + (prefix: string, values: ReadonlyArray): Fragment + } + + readonly join: ( + literal: string, + addParens?: boolean, + fallback?: string + ) => (clauses: ReadonlyArray) => Fragment +} + +/** + * @category constructor + * @since 1.0.0 + */ +export const make: ( + acquirer: Connection.Acquirer, + compiler: Compiler +) => Constructor = internal.make + +/** + * @category constructor + * @since 1.0.0 + */ +export const unsafeFragment: ( + sql: string, + params?: ReadonlyArray | undefined +) => Fragment = internal.unsafeFragment + +/** + * @category constructor + * @since 1.0.0 + */ +export const and: (clauses: ReadonlyArray) => Fragment = internal.and + +/** + * @category constructor + * @since 1.0.0 + */ +export const or: (clauses: ReadonlyArray) => Fragment = internal.or + +/** + * @category constructor + * @since 1.0.0 + */ +export const csv: { + (values: ReadonlyArray): Fragment + (prefix: string, values: ReadonlyArray): Fragment +} = internal.csv + +/** + * @category constructor + * @since 1.0.0 + */ +export const join: ( + literal: string, + addParens?: boolean, + fallback?: string +) => (clauses: ReadonlyArray) => Fragment = internal.join + +/** + * @category compiler + * @since 1.0.0 + */ +export interface Compiler { + readonly compile: ( + statement: Fragment + ) => readonly [sql: string, params: ReadonlyArray] +} + +/** + * @category compiler + * @since 1.0.0 + */ +export const makeCompiler: = any>( + options: { + readonly placeholder: (index: number) => string + readonly onIdentifier: (value: string) => string + readonly onRecordUpdate: ( + placeholders: string, + alias: string, + columns: string, + values: ReadonlyArray> + ) => readonly [sql: string, params: ReadonlyArray] + readonly onCustom: (type: C, placeholder: () => string) => readonly [sql: string, params: ReadonlyArray] + readonly onInsert?: ( + columns: ReadonlyArray, + placeholders: string, + values: ReadonlyArray> + ) => readonly [sql: string, binds: ReadonlyArray] + readonly onRecordUpdateSingle?: ( + columns: ReadonlyArray, + values: ReadonlyArray + ) => readonly [sql: string, params: ReadonlyArray] + } +) => Compiler = internal.makeCompiler + +/** + * @since 1.0.0 + */ +export const defaultEscape: (c: string) => (str: string) => string = internal.defaultEscape + +/** + * @since 1.0.0 + */ +export const primitiveKind: (value: Primitive) => PrimitiveKind = internal.primitiveKind diff --git a/packages/sql/src/Stream.ts b/packages/sql/src/Stream.ts new file mode 100644 index 0000000000..7bed8ce049 --- /dev/null +++ b/packages/sql/src/Stream.ts @@ -0,0 +1,78 @@ +/** + * @since 1.0.0 + */ +import * as Chunk from "effect/Chunk" +import * as Deferred from "effect/Deferred" +import * as Effect from "effect/Effect" +import * as Option from "effect/Option" +import * as Queue from "effect/Queue" +import * as Runtime from "effect/Runtime" +import * as Stream from "effect/Stream" + +/** + * @since 1.0.0 + */ +export const asyncPauseResume = ( + register: (emit: { + readonly single: (item: A) => void + readonly chunk: (chunk: Chunk.Chunk) => void + readonly array: (chunk: ReadonlyArray) => void + readonly fail: (error: E) => void + readonly end: () => void + }) => { + readonly onInterrupt: Effect.Effect + readonly onPause: Effect.Effect + readonly onResume: Effect.Effect + }, + bufferSize = 2 +): Stream.Stream => { + const EOF = Symbol() + return Effect.all([ + Queue.bounded | typeof EOF>(bufferSize), + Deferred.make>(), + Effect.runtime() + ]).pipe( + Effect.flatMap(([queue, deferred, runtime]) => { + return Effect.async, R>((cb) => { + const runFork = Runtime.runFork(runtime) + + // eslint-disable-next-line prefer-const + let effects: { + readonly onInterrupt: Effect.Effect + readonly onPause: Effect.Effect + readonly onResume: Effect.Effect + } + + const offer = (chunk: Chunk.Chunk) => + Queue.isFull(queue).pipe( + Effect.tap((full) => (full ? effects.onPause : Effect.unit)), + Effect.zipRight(Queue.offer(queue, chunk)), + Effect.zipRight(effects.onResume) + ) + + effects = register({ + single: (item) => runFork(offer(Chunk.of(item))), + chunk: (chunk) => runFork(offer(chunk)), + array: (chunk) => runFork(offer(Chunk.unsafeFromArray(chunk))), + fail: (error) => cb(Effect.fail(Option.some(error))), + end: () => cb(Effect.fail(Option.none())) + }) + + return effects.onInterrupt + }).pipe( + Effect.ensuring(Queue.offer(queue, EOF)), + Effect.intoDeferred(deferred), + Effect.forkScoped, + Effect.as( + Stream.repeatEffectChunkOption( + Effect.flatMap( + Queue.take(queue), + (chunk) => chunk === EOF ? Deferred.await(deferred) : Effect.succeed(chunk) + ) + ) + ) + ) + }), + Stream.unwrapScoped + ) +} diff --git a/packages/sql/src/index.ts b/packages/sql/src/index.ts new file mode 100644 index 0000000000..815c80eb6c --- /dev/null +++ b/packages/sql/src/index.ts @@ -0,0 +1,39 @@ +/** + * @since 1.0.0 + */ +export * as Client from "./Client.js" + +/** + * @since 1.0.0 + */ +export * as Connection from "./Connection.js" + +/** + * @since 1.0.0 + */ +export * as Error from "./Error.js" + +/** + * @since 1.0.0 + */ +export * as Migrator from "./Migrator.js" + +/** + * @since 1.0.0 + */ +export * as Resolver from "./Resolver.js" + +/** + * @since 1.0.0 + */ +export * as Schema from "./Schema.js" + +/** + * @since 1.0.0 + */ +export * as Statement from "./Statement.js" + +/** + * @since 1.0.0 + */ +export * as Stream from "./Stream.js" diff --git a/packages/sql/src/internal/client.ts b/packages/sql/src/internal/client.ts new file mode 100644 index 0000000000..ca1691b376 --- /dev/null +++ b/packages/sql/src/internal/client.ts @@ -0,0 +1,155 @@ +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import * as Exit from "effect/Exit" +import { pipe } from "effect/Function" +import * as Option from "effect/Option" +import * as Scope from "effect/Scope" +import type * as Client from "../Client.js" +import type * as Connection from "../Connection.js" +import type * as Error from "../Error.js" +import * as Statement from "../Statement.js" + +/** @internal */ +export const TypeId: Client.TypeId = Symbol.for("@effect/sql/Client") as Client.TypeId + +/** @internal */ +export const TransactionConnection = Context.GenericTag< + Client.TransactionConnection, + readonly [conn: Connection.Connection, counter: number] +>("@effect/sql/Client/TransactionConnection") + +/** @internal */ +export function make({ + acquirer, + beginTransaction = "BEGIN", + commit = "COMMIT", + compiler, + rollback = "ROLLBACK", + rollbackSavepoint = (id) => `ROLLBACK TO SAVEPOINT ${id}`, + savepoint = (id) => `SAVEPOINT ${id}`, + transactionAcquirer +}: Client.Client.MakeOptions): Client.Client { + const getConnection = Effect.flatMap( + Effect.serviceOption(TransactionConnection), + Option.match({ + onNone: () => acquirer, + onSome: ([conn]) => Effect.succeed(conn) + }) + ) + + const makeRootTx: Effect.Effect< + readonly [Scope.CloseableScope | undefined, Connection.Connection, number], + Error.SqlError + > = Effect.flatMap( + Scope.make(), + (scope) => Effect.map(Scope.extend(transactionAcquirer, scope), (conn) => [scope, conn, 0] as const) + ) + + const withTransaction = ( + effect: Effect.Effect + ): Effect.Effect => + Effect.acquireUseRelease( + pipe( + Effect.serviceOption(TransactionConnection), + Effect.flatMap( + Option.match({ + onNone: () => makeRootTx, + onSome: ([conn, count]) => Effect.succeed([undefined, conn, count + 1] as const) + }) + ), + Effect.tap(([, conn, id]) => + id > 0 + ? conn.executeRaw(savepoint(`effect_sql_${id}`)) + : conn.executeRaw(beginTransaction) + ) + ), + ([, conn, id]) => Effect.provideService(effect, TransactionConnection, [conn, id]), + ([scope, conn, id], exit) => { + const effect = Exit.isSuccess(exit) + ? id > 0 + ? Effect.unit + : Effect.orDie(conn.executeRaw(commit)) + : id > 0 + ? Effect.orDie(conn.executeRaw(rollbackSavepoint(`effect_sql_${id}`))) + : Effect.orDie(conn.executeRaw(rollback)) + return scope !== undefined ? Effect.ensuring(effect, Scope.close(scope, exit)) : effect + } + ) + + const client: Client.Client = Object.assign( + Statement.make(getConnection, compiler), + { + [TypeId as Client.TypeId]: TypeId as Client.TypeId, + safe: undefined as any, + withTransaction, + reserve: transactionAcquirer + } + ) + ;(client as any).safe = client + + return client +} + +/** @internal */ +export const defaultTransforms = ( + transformer: (str: string) => string, + nested = true +) => { + const transformValue = (value: any) => { + if (Array.isArray(value)) { + if (value.length === 0 || value[0].constructor !== Object) { + return value + } + return array(value) + } else if (value?.constructor === Object) { + return transformObject(value) + } + return value + } + + const transformObject = (obj: Record): any => { + const newObj: Record = {} + for (const key in obj) { + newObj[transformer(key)] = transformValue(obj[key]) + } + return newObj + } + + const transformArrayNested = ( + rows: ReadonlyArray + ): ReadonlyArray => { + const newRows: Array = new Array(rows.length) + for (let i = 0, len = rows.length; i < len; i++) { + const row = rows[i] + const obj: any = {} + for (const key in row) { + obj[transformer(key)] = transformValue(row[key]) + } + newRows[i] = obj + } + return newRows + } + + const transformArray = ( + rows: ReadonlyArray + ): ReadonlyArray => { + const newRows: Array = new Array(rows.length) + for (let i = 0, len = rows.length; i < len; i++) { + const row = rows[i] + const obj: any = {} + for (const key in row) { + obj[transformer(key)] = row[key] + } + newRows[i] = obj + } + return newRows + } + + const array = nested ? transformArrayNested : transformArray + + return { + value: transformValue, + object: transformObject, + array + } as const +} diff --git a/packages/sql/src/internal/statement.ts b/packages/sql/src/internal/statement.ts new file mode 100644 index 0000000000..f6f6da23f9 --- /dev/null +++ b/packages/sql/src/internal/statement.ts @@ -0,0 +1,734 @@ +import * as Effect from "effect/Effect" +import * as Effectable from "effect/Effectable" +import * as FiberRef from "effect/FiberRef" +import { dual, identity } from "effect/Function" +import { globalValue } from "effect/GlobalValue" +import * as Layer from "effect/Layer" +import * as Option from "effect/Option" +import * as Predicate from "effect/Predicate" +import type { Scope } from "effect/Scope" +import * as Stream from "effect/Stream" +import type * as Connection from "../Connection.js" +import type * as Error from "../Error.js" +import type * as Statement from "../Statement.js" + +/** @internal */ +export const FragmentId: Statement.FragmentId = Symbol.for( + "@effect/sql/Fragment" +) as Statement.FragmentId + +/** @internal */ +export const isFragment = (u: unknown): u is Statement.Fragment => + typeof u === "object" && u !== null && FragmentId in u + +/** @internal */ +export const isParameter = ( + u: Statement.Segment +): u is Statement.Parameter => Predicate.isTagged(u, "Parameter") + +/** @internal */ +export const isCustom = >( + kind: A["kind"] +) => +(u: unknown): u is A => u instanceof CustomImpl && u.kind === kind + +/** @internal */ +export const currentTransformer = globalValue( + "@effect/sql/Statement/currentTransformer", + () => + FiberRef.unsafeMake( + Option.none() + ) +) + +/** @internal */ +export const withTransformer = dual< + ( + f: Statement.Statement.Transformer + ) => (effect: Effect.Effect) => Effect.Effect, + ( + effect: Effect.Effect, + f: Statement.Statement.Transformer + ) => Effect.Effect +>(2, (effect, f) => Effect.locally(effect, currentTransformer, Option.some(f))) + +/** @internal */ +export const withTransformerDisabled = (effect: Effect.Effect) => + Effect.locally(effect, currentTransformer, Option.none()) + +/** @internal */ +export const setTransformer = ( + f: Statement.Statement.Transformer +) => Layer.locallyScoped(currentTransformer, Option.some(f)) + +/** @internal */ +export class StatementPrimitive extends Effectable.Class, Error.SqlError> + implements Statement.Statement +{ + get [FragmentId]() { + return identity + } + + constructor( + readonly segments: ReadonlyArray, + readonly acquirer: Connection.Connection.Acquirer, + readonly compiler: Statement.Compiler + ) { + super() + } + + get withoutTransform(): Effect.Effect, Error.SqlError> { + return Effect.useSpan( + "sql.execute", + (span) => + Effect.withFiberRuntime((fiber) => { + const transform = fiber.getFiberRef(currentTransformer) + const statement = transform._tag === "Some" + ? transform.value(this, make(this.acquirer, this.compiler), fiber.getFiberRefs(), span) + : this + const [sql, params] = statement.compile() + span.attribute("sql.method", "executeWithoutTransform") + span.attribute("sql.query", sql) + return Effect.scoped(Effect.flatMap(this.acquirer, (_) => _.executeWithoutTransform(sql, params))) + }) + ) + } + + get stream(): Stream.Stream { + return Stream.unwrapScoped(Effect.flatMap( + Effect.makeSpanScoped("sql.execute"), + (span) => + Effect.withFiberRuntime, Error.SqlError, Scope>((fiber) => { + const transform = fiber.getFiberRef(currentTransformer) + const statement = transform._tag === "Some" + ? transform.value(this, make(this.acquirer, this.compiler), fiber.getFiberRefs(), span) + : this + const [sql, params] = statement.compile() + span.attribute("sql.method", "executeStream") + span.attribute("sql.query", sql) + return Effect.map(this.acquirer, (_) => _.executeStream(sql, params)) + }) + )) + } + + get values(): Effect.Effect< + ReadonlyArray>, + Error.SqlError + > { + return Effect.useSpan( + "sql.execute", + (span) => + Effect.withFiberRuntime((fiber) => { + const transform = fiber.getFiberRef(currentTransformer) + const statement = transform._tag === "Some" + ? transform.value(this, make(this.acquirer, this.compiler), fiber.getFiberRefs(), span) + : this + const [sql, params] = statement.compile() + span.attribute("sql.method", "executeValues") + span.attribute("sql.query", sql) + return Effect.scoped(Effect.flatMap(this.acquirer, (_) => _.executeValues(sql, params))) + }) + ) + } + + private _compiled: readonly [string, ReadonlyArray] | undefined = undefined + compile() { + if (this._compiled) { + return this._compiled + } + return this._compiled = this.compiler.compile(this) + } + commit(): Effect.Effect, Error.SqlError> { + return Effect.useSpan( + "sql.execute", + (span) => + Effect.withFiberRuntime((fiber) => { + const transform = fiber.getFiberRef(currentTransformer) + const statement = transform._tag === "Some" + ? transform.value(this, make(this.acquirer, this.compiler), fiber.getFiberRefs(), span) + : this + const [sql, params] = statement.compile() + span.attribute("sql.method", "execute") + span.attribute("sql.query", sql) + return Effect.scoped(Effect.flatMap(this.acquirer, (_) => _.execute(sql, params))) + }) + ) + } + toJSON() { + const [sql, params] = this.compile() + return { + _id: "@effect/sql/Statement", + segments: this.segments, + sql, + params + } + } +} + +class FragmentImpl implements Statement.Fragment { + get [FragmentId]() { + return identity + } + constructor(readonly segments: ReadonlyArray) {} +} + +class LiteralImpl implements Statement.Literal { + readonly _tag = "Literal" + constructor( + readonly value: string, + readonly params?: ReadonlyArray + ) {} +} + +class IdentifierImpl implements Statement.Identifier { + readonly _tag = "Identifier" + constructor(readonly value: string) {} +} + +class ParameterImpl implements Statement.Parameter { + readonly _tag = "Parameter" + constructor(readonly value: Statement.Primitive) {} +} + +class ArrayHelperImpl implements Statement.ArrayHelper { + readonly _tag = "ArrayHelper" + constructor(readonly value: ReadonlyArray) {} +} + +class RecordInsertHelperImpl implements Statement.RecordInsertHelper { + readonly _tag = "RecordInsertHelper" + constructor(readonly value: ReadonlyArray>) {} +} + +class RecordUpdateHelperImpl implements Statement.RecordUpdateHelper { + readonly _tag = "RecordUpdateHelper" + constructor( + readonly value: ReadonlyArray>, + readonly alias: string + ) {} +} + +class RecordUpdateHelperSingleImpl implements Statement.RecordUpdateHelperSingle { + readonly _tag = "RecordUpdateHelperSingle" + constructor( + readonly value: Record, + readonly omit: ReadonlyArray + ) {} +} + +class CustomImpl implements Statement.Custom { + readonly _tag = "Custom" + constructor( + readonly kind: T, + readonly i0: A, + readonly i1: B, + readonly i2: C + ) {} +} + +/** @internal */ +export const custom = >( + kind: C["kind"] +) => +(i0: C["i0"], i1: C["i1"], i2: C["i2"]): Statement.Fragment => new FragmentImpl([new CustomImpl(kind, i0, i1, i2)]) + +const isHelper = (u: unknown): u is Statement.Helper => + u instanceof ArrayHelperImpl || + u instanceof RecordInsertHelperImpl || + u instanceof RecordUpdateHelperImpl || + u instanceof RecordUpdateHelperSingleImpl || + u instanceof IdentifierImpl + +const constructorCache = globalValue( + "@effect/sql/Statement/constructorCache", + () => new WeakMap() +) + +/** @internal */ +export const make = ( + acquirer: Connection.Connection.Acquirer, + compiler: Statement.Compiler +): Statement.Constructor => { + if (constructorCache.has(acquirer)) { + return constructorCache.get(acquirer)! + } + const self = Object.assign( + function sql(strings: unknown, ...args: Array): any { + if (Array.isArray(strings) && "raw" in strings) { + return statement( + acquirer, + compiler, + strings as TemplateStringsArray, + ...args + ) + } else if (typeof strings === "string") { + return new IdentifierImpl(strings) + } + + throw "absurd" + }, + { + unsafe( + sql: string, + params?: ReadonlyArray + ) { + return new StatementPrimitive( + [new LiteralImpl(sql, params)], + acquirer, + compiler + ) + }, + literal(sql: string) { + return new FragmentImpl([new LiteralImpl(sql)]) + }, + in(values: ReadonlyArray) { + return new ArrayHelperImpl(values) + }, + insert(value: any) { + return new RecordInsertHelperImpl( + Array.isArray(value) ? value : [value] + ) + }, + update(value: any, omit: any) { + return new RecordUpdateHelperSingleImpl(value, omit) + }, + updateValues(value: any, alias: any) { + return new RecordUpdateHelperImpl(value, alias) + }, + and, + or, + csv, + join + } + ) + + constructorCache.set(acquirer, self) + + return self +} + +/** @internal */ +export const statement = ( + acquirer: Connection.Connection.Acquirer, + compiler: Statement.Compiler, + strings: TemplateStringsArray, + ...args: Array +): Statement.Statement => { + const segments: Array = strings[0].length > 0 ? [new LiteralImpl(strings[0])] : [] + + for (let i = 0; i < args.length; i++) { + const arg = args[i] + + if (isFragment(arg)) { + for (const segment of arg.segments) { + segments.push(segment) + } + } else if (isHelper(arg)) { + segments.push(arg) + } else { + segments.push(new ParameterImpl(arg)) + } + + if (strings[i + 1].length > 0) { + segments.push(new LiteralImpl(strings[i + 1])) + } + } + + return new StatementPrimitive(segments, acquirer, compiler) +} + +/** @internal */ +export const unsafeFragment = ( + sql: string, + params?: ReadonlyArray +): Statement.Fragment => new FragmentImpl([new LiteralImpl(sql, params)]) + +function convertLiteralOrFragment(clause: string | Statement.Fragment): Array { + if (typeof clause === "string") { + return [new LiteralImpl(clause)] + } + return clause.segments as Array +} + +/** @internal */ +export function join(literal: string, addParens = true, fallback = "") { + const literalStatement = new LiteralImpl(literal) + + return (clauses: ReadonlyArray): Statement.Fragment => { + if (clauses.length === 0) { + return unsafeFragment(fallback) + } else if (clauses.length === 1) { + return new FragmentImpl(convertLiteralOrFragment(clauses[0])) + } + + const segments: Array = [] + + if (addParens) { + segments.push(new LiteralImpl("(")) + } + + segments.push.apply(segments, convertLiteralOrFragment(clauses[0])) + + for (let i = 1; i < clauses.length; i++) { + segments.push(literalStatement) + segments.push.apply(segments, convertLiteralOrFragment(clauses[i])) + } + + if (addParens) { + segments.push(new LiteralImpl(")")) + } + + return new FragmentImpl(segments) + } +} + +/** @internal */ +export const and = join(" AND ", true, "1=1") + +/** @internal */ +export const or = join(" OR ", true, "1=1") + +const csvRaw = join(", ", false) + +/** @internal */ +export const csv: { + (values: ReadonlyArray): Statement.Fragment + (prefix: string, values: ReadonlyArray): Statement.Fragment +} = ( + ...args: + | [values: ReadonlyArray] + | [prefix: string, values: ReadonlyArray] +) => { + if (args[args.length - 1].length === 0) { + return unsafeFragment("") + } + + if (args.length === 1) { + return csvRaw(args[0]) + } + + return new FragmentImpl([ + new LiteralImpl(`${args[0]} `), + ...csvRaw(args[1]).segments + ]) +} + +/** @internal */ +class CompilerImpl implements Statement.Compiler { + constructor( + readonly parameterPlaceholder: (index: number) => string, + readonly onIdentifier: (value: string) => string, + readonly onRecordUpdate: ( + placeholders: string, + alias: string, + columns: string, + values: ReadonlyArray> + ) => readonly [sql: string, binds: ReadonlyArray], + readonly onCustom: ( + type: Statement.Custom, + placeholder: () => string + ) => readonly [sql: string, binds: ReadonlyArray], + readonly onInsert?: ( + columns: ReadonlyArray, + placeholders: string, + values: ReadonlyArray> + ) => readonly [sql: string, binds: ReadonlyArray], + readonly onRecordUpdateSingle?: ( + columns: ReadonlyArray, + values: ReadonlyArray + ) => readonly [sql: string, binds: ReadonlyArray] + ) {} + + compile( + statement: Statement.Fragment + ): readonly [sql: string, binds: ReadonlyArray] { + if ((statement as any).__compiled) { + return (statement as any).__compiled + } + + const segments = statement.segments + const len = segments.length + + let sql = "" + const binds: Array = [] + let placeholderCount = 0 + const placeholder = () => this.parameterPlaceholder(++placeholderCount) + + for (let i = 0; i < len; i++) { + const segment = segments[i] + + switch (segment._tag) { + case "Literal": { + sql += segment.value + if (segment.params) { + binds.push.apply(binds, segment.params as any) + } + break + } + + case "Identifier": { + sql += this.onIdentifier(segment.value) + break + } + + case "Parameter": { + sql += placeholder() + binds.push(segment.value) + break + } + + case "ArrayHelper": { + sql += `(${generatePlaceholder(placeholder, segment.value.length)()})` + binds.push.apply(binds, segment.value as any) + break + } + + case "RecordInsertHelper": { + const keys = Object.keys(segment.value[0]) + + if (this.onInsert) { + const [s, b] = this.onInsert( + keys.map(this.onIdentifier), + placeholders( + generatePlaceholder(placeholder, keys.length), + segment.value.length + ), + segment.value.map((record) => + keys.map((key) => extractPrimitive(record[key], this.onCustom, placeholder)) + ) + ) + sql += s + binds.push.apply(binds, b as any) + } else { + sql += `${ + generateColumns( + keys, + this.onIdentifier + ) + } VALUES ${ + placeholders( + generatePlaceholder(placeholder, keys.length), + segment.value.length + ) + }` + + for (let i = 0, len = segment.value.length; i < len; i++) { + for (let j = 0, len = keys.length; j < len; j++) { + binds.push( + extractPrimitive( + segment.value[i]?.[keys[j]] ?? null, + this.onCustom, + placeholder + ) + ) + } + } + } + break + } + + case "RecordUpdateHelperSingle": { + let keys = Object.keys(segment.value) + if (segment.omit.length > 0) { + keys = keys.filter((key) => !segment.omit.includes(key)) + } + if (this.onRecordUpdateSingle) { + const [s, b] = this.onRecordUpdateSingle( + keys.map(this.onIdentifier), + keys.map((key) => + extractPrimitive( + segment.value[key], + this.onCustom, + placeholder + ) + ) + ) + sql += s + binds.push.apply(binds, b as any) + } else { + for (let i = 0, len = keys.length; i < len; i++) { + const column = this.onIdentifier(keys[i]) + if (i === 0) { + sql += `${column} = ${placeholder()}` + } else { + sql += `, ${column} = ${placeholder()}` + } + binds.push( + extractPrimitive( + segment.value[keys[i]], + this.onCustom, + placeholder + ) + ) + } + } + break + } + + case "RecordUpdateHelper": { + const keys = Object.keys(segment.value[0]) + const [s, b] = this.onRecordUpdate( + placeholders( + generatePlaceholder(placeholder, keys.length), + segment.value.length + ), + segment.alias, + generateColumns(keys, this.onIdentifier), + segment.value.map((record) => + keys.map((key) => extractPrimitive(record?.[key], this.onCustom, placeholder)) + ) + ) + sql += s + binds.push.apply(binds, b as any) + break + } + + case "Custom": { + const [s, b] = this.onCustom(segment, placeholder) + sql += s + binds.push.apply(binds, b as any) + break + } + } + } + + return ((statement as any).__compiled = [sql.trim(), binds] as const) + } +} + +/** @internal */ +export const makeCompiler = = any>( + options: { + readonly placeholder: (index: number) => string + readonly onIdentifier: (value: string) => string + readonly onRecordUpdate: ( + placeholders: string, + alias: string, + columns: string, + values: ReadonlyArray> + ) => readonly [sql: string, params: ReadonlyArray] + readonly onCustom: ( + type: C, + placeholder: () => string + ) => readonly [sql: string, params: ReadonlyArray] + readonly onInsert?: ( + columns: ReadonlyArray, + placeholders: string, + values: ReadonlyArray> + ) => readonly [sql: string, binds: ReadonlyArray] + readonly onRecordUpdateSingle?: ( + columns: ReadonlyArray, + values: ReadonlyArray + ) => readonly [sql: string, params: ReadonlyArray] + } +): Statement.Compiler => + new CompilerImpl( + options.placeholder, + options.onIdentifier, + options.onRecordUpdate, + options.onCustom as any, + options.onInsert, + options.onRecordUpdateSingle + ) + +const placeholders = (evaluate: () => string, count: number): string => { + if (count === 0) { + return "" + } + + let result = `(${evaluate()})` + for (let i = 1; i < count; i++) { + result += `,(${evaluate()})` + } + + return result +} + +const generatePlaceholder = (evaluate: () => string, len: number) => { + if (len === 0) { + return () => "" + } else if (len === 1) { + return evaluate + } + + return () => { + let result = evaluate() + for (let i = 1; i < len; i++) { + result += `,${evaluate()}` + } + + return result + } +} + +const generateColumns = ( + keys: ReadonlyArray, + escape: (_: string) => string +) => { + if (keys.length === 0) { + return "()" + } + + let str = `(${escape(keys[0])}` + for (let i = 1; i < keys.length; i++) { + str += `,${escape(keys[i])}` + } + return str + ")" +} + +/** @internal */ +export const defaultEscape = (c: string) => { + const re = new RegExp(c, "g") + const double = c + c + const dot = c + "." + c + return (str: string) => c + str.replace(re, double).replace(/\./g, dot) + c +} + +/** @internal */ +export const primitiveKind = (value: Statement.Primitive): Statement.PrimitiveKind => { + switch (typeof value) { + case "string": + return "string" + case "number": + return "number" + case "boolean": + return "boolean" + case "bigint": + return "bigint" + case "undefined": + return "null" + } + + if (value === null) { + return "null" + } else if (value instanceof Date) { + return "Date" + } else if (value instanceof Uint8Array) { + return "Uint8Array" + } else if (value instanceof Int8Array) { + return "Int8Array" + } + + return "string" +} + +const extractPrimitive = ( + value: Statement.Primitive | Statement.Fragment, + onCustom: ( + type: Statement.Custom, + placeholder: () => string + ) => readonly [sql: string, binds: ReadonlyArray], + placeholder: () => string +): Statement.Primitive => { + if (isFragment(value)) { + const head = value.segments[0] + if (head._tag === "Custom") { + const compiled = onCustom(head, placeholder) + return compiled[1][0] ?? null + } else if (head._tag === "Parameter") { + return head.value + } + return null + } + return value +} diff --git a/packages/sql/test/index.test.ts b/packages/sql/test/index.test.ts new file mode 100644 index 0000000000..7c743e0528 --- /dev/null +++ b/packages/sql/test/index.test.ts @@ -0,0 +1,8 @@ +import { assert, describe, it } from "vitest" + +// TODO: implement a test suite +describe("sql", () => { + it("should work", () => { + assert.ok(true) + }) +}) diff --git a/packages/sql/tsconfig.build.json b/packages/sql/tsconfig.build.json new file mode 100644 index 0000000000..fd1f3bbd27 --- /dev/null +++ b/packages/sql/tsconfig.build.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.src.json", + "references": [ + { "path": "../effect" }, + { "path": "../platform" }, + { "path": "../schema" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/build.tsbuildinfo", + "outDir": "build/esm", + "declarationDir": "build/dts", + "stripInternal": true + } +} diff --git a/packages/sql/tsconfig.examples.json b/packages/sql/tsconfig.examples.json new file mode 100644 index 0000000000..718637d3f2 --- /dev/null +++ b/packages/sql/tsconfig.examples.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["examples"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../platform" }, + { "path": "../schema" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/examples.tsbuildinfo", + "rootDir": "examples", + "noEmit": true + } +} diff --git a/packages/sql/tsconfig.json b/packages/sql/tsconfig.json new file mode 100644 index 0000000000..3edbf6b8a5 --- /dev/null +++ b/packages/sql/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "include": [], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "tsconfig.test.json" }, + { "path": "tsconfig.examples.json" } + ] +} diff --git a/packages/sql/tsconfig.src.json b/packages/sql/tsconfig.src.json new file mode 100644 index 0000000000..fe0ac8a681 --- /dev/null +++ b/packages/sql/tsconfig.src.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src"], + "references": [ + { "path": "../effect" }, + { "path": "../platform" }, + { "path": "../schema" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/src.tsbuildinfo", + "rootDir": "src", + "outDir": "build/src" + } +} diff --git a/packages/sql/tsconfig.test.json b/packages/sql/tsconfig.test.json new file mode 100644 index 0000000000..380524224f --- /dev/null +++ b/packages/sql/tsconfig.test.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["test"], + "references": [ + { "path": "tsconfig.src.json" }, + { "path": "../effect" }, + { "path": "../platform" }, + { "path": "../schema" } + ], + "compilerOptions": { + "tsBuildInfoFile": ".tsbuildinfo/test.tsbuildinfo", + "rootDir": "test", + "noEmit": true + } +} diff --git a/packages/sql/vitest.config.ts b/packages/sql/vitest.config.ts new file mode 100644 index 0000000000..0411095f25 --- /dev/null +++ b/packages/sql/vitest.config.ts @@ -0,0 +1,6 @@ +import { mergeConfig, type UserConfigExport } from "vitest/config" +import shared from "../../vitest.shared.js" + +const config: UserConfigExport = {} + +export default mergeConfig(shared, config) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0cac2c07b7..c9900cb9fd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -476,6 +476,134 @@ importers: version: 3.22.4 publishDirectory: dist + packages/sql: + devDependencies: + '@effect/platform': + specifier: workspace:^ + version: link:../platform/dist + '@effect/schema': + specifier: workspace:^ + version: link:../schema/dist + effect: + specifier: workspace:^ + version: link:../effect/dist + publishDirectory: dist + + packages/sql-mssql: + dependencies: + tedious: + specifier: ^18 + version: 18.1.0 + devDependencies: + '@effect/platform': + specifier: workspace:^ + version: link:../platform/dist + '@effect/sql': + specifier: workspace:^ + version: link:../sql/dist + effect: + specifier: workspace:^ + version: link:../effect/dist + publishDirectory: dist + + packages/sql-mysql2: + dependencies: + mysql2: + specifier: ^3 + version: 3.9.4 + devDependencies: + '@effect/platform': + specifier: workspace:^ + version: link:../platform/dist + '@effect/sql': + specifier: workspace:^ + version: link:../sql/dist + effect: + specifier: workspace:^ + version: link:../effect/dist + publishDirectory: dist + + packages/sql-pg: + dependencies: + postgres: + specifier: ^3.4.4 + version: 3.4.4 + devDependencies: + '@effect/platform': + specifier: workspace:^ + version: link:../platform/dist + '@effect/sql': + specifier: workspace:^ + version: link:../sql/dist + effect: + specifier: workspace:^ + version: link:../effect/dist + publishDirectory: dist + + packages/sql-sqlite-bun: + devDependencies: + '@effect/platform': + specifier: workspace:^ + version: link:../platform/dist + '@effect/sql': + specifier: workspace:^ + version: link:../sql/dist + bun-types: + specifier: 1.0.33 + version: 1.0.33 + effect: + specifier: workspace:^ + version: link:../effect/dist + publishDirectory: dist + + packages/sql-sqlite-node: + dependencies: + better-sqlite3: + specifier: ^9.5.0 + version: 9.5.0 + devDependencies: + '@effect/platform': + specifier: workspace:^ + version: link:../platform/dist + '@effect/sql': + specifier: workspace:^ + version: link:../sql/dist + '@types/better-sqlite3': + specifier: ^7.6.9 + version: 7.6.9 + effect: + specifier: workspace:^ + version: link:../effect/dist + publishDirectory: dist + + packages/sql-sqlite-react-native: + dependencies: + react-native-quick-sqlite: + specifier: ^8.0.6 + version: 8.0.6(react-native@0.73.6)(react@18.2.0) + devDependencies: + '@effect/sql': + specifier: workspace:^ + version: link:../sql/dist + effect: + specifier: workspace:^ + version: link:../effect/dist + publishDirectory: dist + + packages/sql-sqlite-wasm: + dependencies: + '@sqlite.org/sqlite-wasm': + specifier: 3.45.2-build1 + version: 3.45.2-build1 + devDependencies: + '@effect/sql': + specifier: workspace:^ + version: link:../sql/dist + effect: + specifier: workspace:^ + version: link:../effect/dist + publishDirectory: dist + packages/typeclass: devDependencies: effect: @@ -506,7 +634,172 @@ packages: dependencies: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - dev: true + + /@azure/abort-controller@1.1.0: + resolution: {integrity: sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==} + engines: {node: '>=12.0.0'} + dependencies: + tslib: 2.6.2 + dev: false + + /@azure/abort-controller@2.1.2: + resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} + engines: {node: '>=18.0.0'} + dependencies: + tslib: 2.6.2 + dev: false + + /@azure/core-auth@1.7.2: + resolution: {integrity: sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==} + engines: {node: '>=18.0.0'} + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-util': 1.9.0 + tslib: 2.6.2 + dev: false + + /@azure/core-client@1.9.2: + resolution: {integrity: sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==} + engines: {node: '>=18.0.0'} + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.7.2 + '@azure/core-rest-pipeline': 1.15.2 + '@azure/core-tracing': 1.1.2 + '@azure/core-util': 1.9.0 + '@azure/logger': 1.1.2 + tslib: 2.6.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@azure/core-http-compat@2.1.2: + resolution: {integrity: sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ==} + engines: {node: '>=18.0.0'} + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-client': 1.9.2 + '@azure/core-rest-pipeline': 1.15.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@azure/core-lro@2.7.2: + resolution: {integrity: sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==} + engines: {node: '>=18.0.0'} + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-util': 1.9.0 + '@azure/logger': 1.1.2 + tslib: 2.6.2 + dev: false + + /@azure/core-paging@1.6.2: + resolution: {integrity: sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==} + engines: {node: '>=18.0.0'} + dependencies: + tslib: 2.6.2 + dev: false + + /@azure/core-rest-pipeline@1.15.2: + resolution: {integrity: sha512-BmWfpjc/QXc2ipHOh6LbUzp3ONCaa6xzIssTU0DwH9bbYNXJlGUL6tujx5TrbVd/QQknmS+vlQJGrCq2oL1gZA==} + engines: {node: '>=18.0.0'} + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.7.2 + '@azure/core-tracing': 1.1.2 + '@azure/core-util': 1.9.0 + '@azure/logger': 1.1.2 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.4 + tslib: 2.6.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@azure/core-tracing@1.1.2: + resolution: {integrity: sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==} + engines: {node: '>=18.0.0'} + dependencies: + tslib: 2.6.2 + dev: false + + /@azure/core-util@1.9.0: + resolution: {integrity: sha512-AfalUQ1ZppaKuxPPMsFEUdX6GZPB3d9paR9d/TTL7Ow2De8cJaC7ibi7kWVlFAVPCYo31OcnGymc0R89DX8Oaw==} + engines: {node: '>=18.0.0'} + dependencies: + '@azure/abort-controller': 2.1.2 + tslib: 2.6.2 + dev: false + + /@azure/identity@3.4.2: + resolution: {integrity: sha512-0q5DL4uyR0EZ4RXQKD8MadGH6zTIcloUoS/RVbCpNpej4pwte0xpqYxk8K97Py2RiuUvI7F4GXpoT4046VfufA==} + engines: {node: '>=14.0.0'} + dependencies: + '@azure/abort-controller': 1.1.0 + '@azure/core-auth': 1.7.2 + '@azure/core-client': 1.9.2 + '@azure/core-rest-pipeline': 1.15.2 + '@azure/core-tracing': 1.1.2 + '@azure/core-util': 1.9.0 + '@azure/logger': 1.1.2 + '@azure/msal-browser': 3.13.0 + '@azure/msal-node': 2.7.0 + events: 3.3.0 + jws: 4.0.0 + open: 8.4.2 + stoppable: 1.1.0 + tslib: 2.6.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@azure/keyvault-keys@4.8.0: + resolution: {integrity: sha512-jkuYxgkw0aaRfk40OQhFqDIupqblIOIlYESWB6DKCVDxQet1pyv86Tfk9M+5uFM0+mCs6+MUHU+Hxh3joiUn4Q==} + engines: {node: '>=18.0.0'} + dependencies: + '@azure/abort-controller': 1.1.0 + '@azure/core-auth': 1.7.2 + '@azure/core-client': 1.9.2 + '@azure/core-http-compat': 2.1.2 + '@azure/core-lro': 2.7.2 + '@azure/core-paging': 1.6.2 + '@azure/core-rest-pipeline': 1.15.2 + '@azure/core-tracing': 1.1.2 + '@azure/core-util': 1.9.0 + '@azure/logger': 1.1.2 + tslib: 2.6.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@azure/logger@1.1.2: + resolution: {integrity: sha512-l170uE7bsKpIU6B/giRc9i4NI0Mj+tANMMMxf7Zi/5cKzEqPayP7+X1WPrG7e+91JgY8N+7K7nF2WOi7iVhXvg==} + engines: {node: '>=18.0.0'} + dependencies: + tslib: 2.6.2 + dev: false + + /@azure/msal-browser@3.13.0: + resolution: {integrity: sha512-fD906nmJei3yE7la6DZTdUtXKvpwzJURkfsiz9747Icv4pit77cegSm6prJTKLQ1fw4iiZzrrWwxnhMLrTf5gQ==} + engines: {node: '>=0.8.0'} + dependencies: + '@azure/msal-common': 14.9.0 + dev: false + + /@azure/msal-common@14.9.0: + resolution: {integrity: sha512-yzBPRlWPnTBeixxLNI3BBIgF5/bHpbhoRVuuDBnYjCyWRavaPUsKAHUDYLqpGkBLDciA6TCc6GOxN4/S3WiSxg==} + engines: {node: '>=0.8.0'} + dev: false + + /@azure/msal-node@2.7.0: + resolution: {integrity: sha512-wXD8LkUvHICeSWZydqg6o8Yvv+grlBEcmLGu+QEI4FcwFendbTEZrlSygnAXXSOCVaGAirWLchca35qrgpO6Jw==} + engines: {node: '>=16'} + dependencies: + '@azure/msal-common': 14.9.0 + jsonwebtoken: 9.0.2 + uuid: 8.3.2 + dev: false /@babel/cli@7.24.1(@babel/core@7.24.3): resolution: {integrity: sha512-HbmrtxyFUr34LwAlV9jS+sSIjUp4FpdtIMGwgufY3AsxrIfsh/HxlMTywsONAZsU0RMYbZtbZFpUCrSGs7o0EA==} @@ -542,12 +835,15 @@ packages: dependencies: '@babel/highlight': 7.24.2 picocolors: 1.0.0 - dev: true /@babel/compat-data@7.24.1: resolution: {integrity: sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==} engines: {node: '>=6.9.0'} - dev: true + + /@babel/compat-data@7.24.4: + resolution: {integrity: sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==} + engines: {node: '>=6.9.0'} + dev: false /@babel/core@7.24.3: resolution: {integrity: sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==} @@ -570,7 +866,6 @@ packages: semver: 6.3.1 transitivePeerDependencies: - supports-color - dev: true /@babel/generator@7.12.17: resolution: {integrity: sha512-DSA7ruZrY4WI8VxuS1jWSRezFnghEoYEFrZcw9BizQRmOZiUsiHl59+qEARGPqPikwA/GPTyRCi7isuCK/oyqg==} @@ -588,14 +883,19 @@ packages: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 - dev: true /@babel/helper-annotate-as-pure@7.22.5: resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.0 - dev: true + + /@babel/helper-builder-binary-assignment-operator-visitor@7.22.15: + resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + dev: false /@babel/helper-compilation-targets@7.23.6: resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} @@ -606,7 +906,6 @@ packages: browserslist: 4.23.0 lru-cache: 5.1.1 semver: 6.3.1 - dev: true /@babel/helper-create-class-features-plugin@7.24.1(@babel/core@7.24.3): resolution: {integrity: sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA==} @@ -624,12 +923,55 @@ packages: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 semver: 6.3.1 - dev: true + + /@babel/helper-create-class-features-plugin@7.24.4(@babel/core@7.24.3): + resolution: {integrity: sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.3) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + semver: 6.3.1 + dev: false + + /@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.3): + resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-annotate-as-pure': 7.22.5 + regexpu-core: 5.3.2 + semver: 6.3.1 + dev: false + + /@babel/helper-define-polyfill-provider@0.6.1(@babel/core@7.24.3): + resolution: {integrity: sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.24.0 + debug: 4.3.4 + lodash.debounce: 4.0.8 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + dev: false /@babel/helper-environment-visitor@7.22.20: resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-function-name@7.23.0: resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} @@ -637,28 +979,24 @@ packages: dependencies: '@babel/template': 7.24.0 '@babel/types': 7.24.0 - dev: true /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.0 - dev: true /@babel/helper-member-expression-to-functions@7.23.0: resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.0 - dev: true /@babel/helper-module-imports@7.24.3: resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.0 - dev: true /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.3): resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} @@ -672,19 +1010,28 @@ packages: '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 - dev: true /@babel/helper-optimise-call-expression@7.22.5: resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.0 - dev: true /@babel/helper-plugin-utils@7.24.0: resolution: {integrity: sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==} engines: {node: '>=6.9.0'} - dev: true + + /@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.3): + resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-wrap-function': 7.22.20 + dev: false /@babel/helper-replace-supers@7.24.1(@babel/core@7.24.3): resolution: {integrity: sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==} @@ -696,28 +1043,24 @@ packages: '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-member-expression-to-functions': 7.23.0 '@babel/helper-optimise-call-expression': 7.22.5 - dev: true /@babel/helper-simple-access@7.22.5: resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.0 - dev: true /@babel/helper-skip-transparent-expression-wrappers@7.22.5: resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.0 - dev: true /@babel/helper-split-export-declaration@7.22.6: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.0 - dev: true /@babel/helper-string-parser@7.23.4: resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} @@ -727,17 +1070,23 @@ packages: /@babel/helper-string-parser@7.24.1: resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-validator-identifier@7.22.20: resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-validator-option@7.23.5: resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} engines: {node: '>=6.9.0'} - dev: true + + /@babel/helper-wrap-function@7.22.20: + resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-function-name': 7.23.0 + '@babel/template': 7.24.0 + '@babel/types': 7.24.0 + dev: false /@babel/helpers@7.24.1: resolution: {integrity: sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==} @@ -748,7 +1097,6 @@ packages: '@babel/types': 7.24.0 transitivePeerDependencies: - supports-color - dev: true /@babel/highlight@7.23.4: resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} @@ -767,7 +1115,6 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.0.0 - dev: true /@babel/parser@7.23.9: resolution: {integrity: sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==} @@ -783,16 +1130,215 @@ packages: hasBin: true dependencies: '@babel/types': 7.24.0 - dev: true - /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.3): + /@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.4(@babel/core@7.24.3): + resolution: {integrity: sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-optional-chaining': 7.24.1(@babel/core@7.24.3) + dev: false + + /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.24.3): + resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.3) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.3) + dev: false + + /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.24.3): + resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-proposal-export-default-from@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-+0hrgGGV3xyYIjOrD/bUZk/iUwOIGuoANfRfVg1cPhYBxF+TIXSEcc42DqzBICmWsnAQ+SfKedY0bj8QD+LuMg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-export-default-from': 7.24.1(@babel/core@7.24.3) + dev: false + + /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.24.3): + resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.3) + dev: false + + /@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.24.3): + resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.3) + dev: false + + /@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.24.3): + resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/compat-data': 7.24.1 + '@babel/core': 7.24.3 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-transform-parameters': 7.24.1(@babel/core@7.24.3) + dev: false + + /@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.24.3): + resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.3) + dev: false + + /@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.24.3): + resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.3) + dev: false + + /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.3): + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + dev: false + + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.3): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.3): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.3): + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-syntax-export-default-from@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-cNXSxv9eTkGUtd0PsNMK8Yx5xeScxfpWOUAxE+ZPAXXEcAMOC3fk7LRdXq5fvpra2pLx2p1YtkAhpUbB2SwaRA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.3): resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true /@babel/plugin-syntax-flow@7.24.1(@babel/core@7.24.3): resolution: {integrity: sha512-sxi2kLTI5DeW5vDtMUsk4mTPwvlUDbjOnoWayhynCwrw4QXRld4QEYwqzY8JmQXaJUtgUuCIurtSRH5sn4c7mA==} @@ -802,7 +1348,44 @@ packages: dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true + + /@babel/plugin-syntax-import-assertions@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-syntax-import-attributes@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.3): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false /@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.24.3): resolution: {integrity: sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==} @@ -812,7 +1395,15 @@ packages: dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true + + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.3): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.3): resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} @@ -821,130 +1412,803 @@ packages: dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.3): - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.3): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true + dev: false - /@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.3): - resolution: {integrity: sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==} - engines: {node: '>=6.9.0'} + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true + dev: false - /@babel/plugin-transform-class-properties@7.24.1(@babel/core@7.24.3): - resolution: {integrity: sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==} - engines: {node: '>=6.9.0'} + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.3) '@babel/helper-plugin-utils': 7.24.0 - dev: true + dev: false - /@babel/plugin-transform-export-namespace-from@7.24.1(@babel/core@7.24.3): - resolution: {integrity: sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==} + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + + /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.3): + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.3) - dev: true + dev: false - /@babel/plugin-transform-flow-strip-types@7.24.1(@babel/core@7.24.3): - resolution: {integrity: sha512-iIYPIWt3dUmUKKE10s3W+jsQ3icFkw0JyRVyY1B7G4yK/nngAOHLVx8xlhA6b/Jzl/Y0nis8gjqhqKtRDQqHWQ==} + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.3): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-flow': 7.24.1(@babel/core@7.24.3) - dev: true + dev: false - /@babel/plugin-transform-modules-commonjs@7.24.1(@babel/core@7.24.3): - resolution: {integrity: sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==} + /@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3) '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-simple-access': 7.22.5 - dev: true - /@babel/plugin-transform-nullish-coalescing-operator@7.24.1(@babel/core@7.24.3): - resolution: {integrity: sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==} + /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.3): + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-arrow-functions@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.3) - dev: true + dev: false - /@babel/plugin-transform-optional-chaining@7.24.1(@babel/core@7.24.3): - resolution: {integrity: sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==} + /@babel/plugin-transform-async-generator-functions@7.24.3(@babel/core@7.24.3): + resolution: {integrity: sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 + '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.3) - dev: true + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.3) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.3) + dev: false - /@babel/plugin-transform-private-methods@7.24.1(@babel/core@7.24.3): - resolution: {integrity: sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==} + /@babel/plugin-transform-async-to-generator@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.3) + '@babel/helper-module-imports': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.3) + dev: false + + /@babel/plugin-transform-block-scoped-functions@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-block-scoping@7.24.4(@babel/core@7.24.3): + resolution: {integrity: sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-class-properties@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + + /@babel/plugin-transform-class-static-block@7.24.4(@babel/core@7.24.3): + resolution: {integrity: sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-create-class-features-plugin': 7.24.4(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.3) + dev: false + + /@babel/plugin-transform-classes@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.3) + '@babel/helper-split-export-declaration': 7.22.6 + globals: 11.12.0 + dev: false + + /@babel/plugin-transform-computed-properties@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/template': 7.24.0 + dev: false + + /@babel/plugin-transform-destructuring@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-dotall-regex@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-duplicate-keys@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-dynamic-import@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.3) + dev: false + + /@babel/plugin-transform-exponentiation-operator@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-export-namespace-from@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.3) + + /@babel/plugin-transform-flow-strip-types@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-iIYPIWt3dUmUKKE10s3W+jsQ3icFkw0JyRVyY1B7G4yK/nngAOHLVx8xlhA6b/Jzl/Y0nis8gjqhqKtRDQqHWQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-flow': 7.24.1(@babel/core@7.24.3) + + /@babel/plugin-transform-for-of@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + dev: false + + /@babel/plugin-transform-function-name@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-json-strings@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.3) + dev: false + + /@babel/plugin-transform-literals@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-logical-assignment-operators@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.3) + dev: false + + /@babel/plugin-transform-member-expression-literals@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-modules-amd@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-modules-commonjs@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-simple-access': 7.22.5 + + /@babel/plugin-transform-modules-systemjs@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-validator-identifier': 7.22.20 + dev: false + + /@babel/plugin-transform-modules-umd@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.24.3): + resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-new-target@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-nullish-coalescing-operator@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.3) + + /@babel/plugin-transform-numeric-separator@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.3) + dev: false + + /@babel/plugin-transform-object-rest-spread@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-transform-parameters': 7.24.1(@babel/core@7.24.3) + dev: false + + /@babel/plugin-transform-object-super@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.3) + dev: false + + /@babel/plugin-transform-optional-catch-binding@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.3) + dev: false + + /@babel/plugin-transform-optional-chaining@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.3) + + /@babel/plugin-transform-parameters@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-private-methods@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + + /@babel/plugin-transform-private-property-in-object@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.3) + dev: false + + /@babel/plugin-transform-property-literals@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-react-display-name@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-react-jsx-self@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-kDJgnPujTmAZ/9q2CN4m2/lRsUUPDvsG3+tSHWUJIzMGTt5U/b/fwWd3RO3n+5mjLrsBrVa5eKFRVSQbi3dF1w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-react-jsx-source@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-1v202n7aUq4uXAieRTKcwPzNyphlCuqHHDcdSNc+vdhoTEZcFMh+L5yZuCmGaIO7bs1nJUNfHB89TZyoL48xNA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.24.3): + resolution: {integrity: sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-module-imports': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.3) + '@babel/types': 7.24.0 + dev: false + + /@babel/plugin-transform-regenerator@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + regenerator-transform: 0.15.2 + dev: false + + /@babel/plugin-transform-reserved-words@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-runtime@7.24.3(@babel/core@7.24.3): + resolution: {integrity: sha512-J0BuRPNlNqlMTRJ72eVptpt9VcInbxO6iP3jaxr+1NPhC0UkKL+6oeX6VXMEYdADnuqmMmsBspt4d5w8Y/TCbQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-module-imports': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + babel-plugin-polyfill-corejs2: 0.4.10(@babel/core@7.24.3) + babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.3) + babel-plugin-polyfill-regenerator: 0.6.1(@babel/core@7.24.3) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@babel/plugin-transform-shorthand-properties@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-spread@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + dev: false + + /@babel/plugin-transform-sticky-regex@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-template-literals@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-typeof-symbol@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-typescript@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-liYSESjX2fZ7JyBFkYG78nfvHlMKE6IpNdTVnxmlYUR+j5ZLsitFbaAE+eJSK2zPPkNWNw4mXL51rQ8WrvdK0w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.3) + + /@babel/plugin-transform-unicode-escapes@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-unicode-property-regex@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-unicode-regex@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/plugin-transform-unicode-sets-regex@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.0 + dev: false + + /@babel/preset-env@7.24.4(@babel/core@7.24.3): + resolution: {integrity: sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/compat-data': 7.24.4 + '@babel/core': 7.24.3 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-validator-option': 7.23.5 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.4(@babel/core@7.24.3) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.3) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.3) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.3) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.3) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-import-assertions': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-syntax-import-attributes': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.3) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.3) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.3) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.3) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.3) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.3) + '@babel/plugin-transform-arrow-functions': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-async-generator-functions': 7.24.3(@babel/core@7.24.3) + '@babel/plugin-transform-async-to-generator': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-block-scoped-functions': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-block-scoping': 7.24.4(@babel/core@7.24.3) + '@babel/plugin-transform-class-properties': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-class-static-block': 7.24.4(@babel/core@7.24.3) + '@babel/plugin-transform-classes': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-computed-properties': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-destructuring': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-dotall-regex': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-duplicate-keys': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-dynamic-import': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-exponentiation-operator': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-export-namespace-from': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-for-of': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-function-name': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-json-strings': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-literals': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-logical-assignment-operators': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-member-expression-literals': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-modules-amd': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-modules-systemjs': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-modules-umd': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.24.3) + '@babel/plugin-transform-new-target': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-nullish-coalescing-operator': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-numeric-separator': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-object-rest-spread': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-object-super': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-optional-catch-binding': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-optional-chaining': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-parameters': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-private-methods': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-private-property-in-object': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-property-literals': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-regenerator': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-reserved-words': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-shorthand-properties': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-spread': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-sticky-regex': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-template-literals': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-typeof-symbol': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-unicode-escapes': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-unicode-property-regex': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-unicode-regex': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-unicode-sets-regex': 7.24.1(@babel/core@7.24.3) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.3) + babel-plugin-polyfill-corejs2: 0.4.10(@babel/core@7.24.3) + babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.3) + babel-plugin-polyfill-regenerator: 0.6.1(@babel/core@7.24.3) + core-js-compat: 3.36.1 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: false - /@babel/plugin-transform-typescript@7.24.1(@babel/core@7.24.3): - resolution: {integrity: sha512-liYSESjX2fZ7JyBFkYG78nfvHlMKE6IpNdTVnxmlYUR+j5ZLsitFbaAE+eJSK2zPPkNWNw4mXL51rQ8WrvdK0w==} + /@babel/preset-flow@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-sWCV2G9pcqZf+JHyv/RyqEIpFypxdCSxWIxQjpdaQxenNog7cN1pr76hg8u0Fz8Qgg0H4ETkGcJnXL8d4j0PPA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.3) '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.3) - dev: true + '@babel/helper-validator-option': 7.23.5 + '@babel/plugin-transform-flow-strip-types': 7.24.1(@babel/core@7.24.3) - /@babel/preset-flow@7.24.1(@babel/core@7.24.3): - resolution: {integrity: sha512-sWCV2G9pcqZf+JHyv/RyqEIpFypxdCSxWIxQjpdaQxenNog7cN1pr76hg8u0Fz8Qgg0H4ETkGcJnXL8d4j0PPA==} - engines: {node: '>=6.9.0'} + /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.3): + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-transform-flow-strip-types': 7.24.1(@babel/core@7.24.3) - dev: true + '@babel/types': 7.24.0 + esutils: 2.0.3 + dev: false /@babel/preset-typescript@7.24.1(@babel/core@7.24.3): resolution: {integrity: sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ==} @@ -958,7 +2222,6 @@ packages: '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.3) '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.3) '@babel/plugin-transform-typescript': 7.24.1(@babel/core@7.24.3) - dev: true /@babel/register@7.23.7(@babel/core@7.24.3): resolution: {integrity: sha512-EjJeB6+kvpk+Y5DAkEAmbOBEFkh9OASx0huoEkqYTFxAZHzOAX2Oh5uwAUuL2rUddqfM0SA+KPXV2TbzoZ2kvQ==} @@ -972,14 +2235,16 @@ packages: make-dir: 2.1.0 pirates: 4.0.6 source-map-support: 0.5.21 - dev: true + + /@babel/regjsgen@0.8.0: + resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} + dev: false /@babel/runtime@7.23.9: resolution: {integrity: sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 - dev: true /@babel/template@7.24.0: resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} @@ -988,7 +2253,6 @@ packages: '@babel/code-frame': 7.24.2 '@babel/parser': 7.24.1 '@babel/types': 7.24.0 - dev: true /@babel/traverse@7.24.1: resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==} @@ -1006,7 +2270,6 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color - dev: true /@babel/types@7.23.9: resolution: {integrity: sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==} @@ -1024,7 +2287,6 @@ packages: '@babel/helper-string-parser': 7.24.1 '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 - dev: true /@bcoe/v8-coverage@0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -1277,7 +2539,7 @@ packages: dependencies: doctrine: 3.0.0 glob: 10.3.10 - markdown-toc: github.com/effect-ts/markdown-toc/4bfeb0f140105440ea0d12df2fa23199cc3ec1d5 + markdown-toc: github.com/effect-ts/markdown-toc/3ea4550bf1352c612aa8b9e582dc263a89f2b64d prettier: 3.2.5 tsx: 4.7.1 typescript: 5.4.3 @@ -1757,6 +3019,16 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@hapi/hoek@9.3.0: + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + dev: false + + /@hapi/topo@5.1.0: + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + dependencies: + '@hapi/hoek': 9.3.0 + dev: false + /@humanwhocodes/config-array@0.11.14: resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -1793,11 +3065,33 @@ packages: wrap-ansi-cjs: /wrap-ansi@7.0.0 dev: true + /@isaacs/ttlcache@1.4.1: + resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} + engines: {node: '>=12'} + dev: false + /@istanbuljs/schema@0.1.3: resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} dev: true + /@jest/create-cache-key-function@29.7.0: + resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + dev: false + + /@jest/environment@29.7.0: + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.11.30 + jest-mock: 29.7.0 + dev: false + /@jest/expect-utils@29.7.0: resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1805,12 +3099,34 @@ packages: jest-get-type: 29.6.3 dev: true + /@jest/fake-timers@29.7.0: + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 20.11.30 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + dev: false + /@jest/schemas@29.6.3: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@sinclair/typebox': 0.27.8 - dev: true + + /@jest/types@26.6.2: + resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==} + engines: {node: '>= 10.14.2'} + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 20.11.30 + '@types/yargs': 15.0.19 + chalk: 4.1.2 + dev: false /@jest/types@29.6.3: resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} @@ -1822,7 +3138,6 @@ packages: '@types/node': 20.11.30 '@types/yargs': 17.0.32 chalk: 4.1.2 - dev: true /@jridgewell/gen-mapping@0.3.5: resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} @@ -1831,28 +3146,34 @@ packages: '@jridgewell/set-array': 1.2.1 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.25 - dev: true /@jridgewell/resolve-uri@3.1.2: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - dev: true /@jridgewell/set-array@1.2.1: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} - dev: true + + /@jridgewell/source-map@0.3.6: + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + dev: false /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true /@jridgewell/trace-mapping@0.3.25: resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - dev: true + + /@js-joda/core@5.6.2: + resolution: {integrity: sha512-ow4R+7C24xeTjiMTTZ4k6lvxj7MRBqvqLCQjThQff3RjOmIMokMP20LNYVFhGafJtUx/Xo2Qp4qU8eNoTVH0SA==} + dev: false /@lmdb/lmdb-darwin-arm64@3.0.0: resolution: {integrity: sha512-iuJO2xaqKFw1AhHaFTZajHE2VaN53tAZO3gUkT7sbOX0MVDSYvmdLNMLEehsrz2Yt5j4QyO/0p1xkFYqeUUxjA==} @@ -2293,46 +3614,390 @@ packages: os: [win32] requiresBuild: true dev: false - optional: true + optional: true + + /@parcel/watcher@2.4.1: + resolution: {integrity: sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==} + engines: {node: '>= 10.0.0'} + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.5 + node-addon-api: 7.1.0 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.4.1 + '@parcel/watcher-darwin-arm64': 2.4.1 + '@parcel/watcher-darwin-x64': 2.4.1 + '@parcel/watcher-freebsd-x64': 2.4.1 + '@parcel/watcher-linux-arm-glibc': 2.4.1 + '@parcel/watcher-linux-arm64-glibc': 2.4.1 + '@parcel/watcher-linux-arm64-musl': 2.4.1 + '@parcel/watcher-linux-x64-glibc': 2.4.1 + '@parcel/watcher-linux-x64-musl': 2.4.1 + '@parcel/watcher-win32-arm64': 2.4.1 + '@parcel/watcher-win32-ia32': 2.4.1 + '@parcel/watcher-win32-x64': 2.4.1 + dev: false + + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + dev: true + optional: true + + /@pnpm/deps.graph-sequencer@1.0.0: + resolution: {integrity: sha512-vWWVbYYBBN/kweokmURicokyg7crzcDZo9/naziv8B8RSWrLWFpq5Xl0ro6QCQKgRmb6O78Qy9uQT+Fp79RxsA==} + engines: {node: '>=16.14'} + dev: true + + /@polka/url@1.0.0-next.25: + resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} + dev: true + + /@react-native-community/cli-clean@12.3.6: + resolution: {integrity: sha512-gUU29ep8xM0BbnZjwz9MyID74KKwutq9x5iv4BCr2im6nly4UMf1B1D+V225wR7VcDGzbgWjaezsJShLLhC5ig==} + dependencies: + '@react-native-community/cli-tools': 12.3.6 + chalk: 4.1.2 + execa: 5.1.1 + transitivePeerDependencies: + - encoding + dev: false + + /@react-native-community/cli-config@12.3.6: + resolution: {integrity: sha512-JGWSYQ9EAK6m2v0abXwFLEfsqJ1zkhzZ4CV261QZF9MoUNB6h57a274h1MLQR9mG6Tsh38wBUuNfEPUvS1vYew==} + dependencies: + '@react-native-community/cli-tools': 12.3.6 + chalk: 4.1.2 + cosmiconfig: 5.2.1 + deepmerge: 4.3.1 + glob: 7.2.3 + joi: 17.12.3 + transitivePeerDependencies: + - encoding + dev: false + + /@react-native-community/cli-debugger-ui@12.3.6: + resolution: {integrity: sha512-SjUKKsx5FmcK9G6Pb6UBFT0s9JexVStK5WInmANw75Hm7YokVvHEgtprQDz2Uvy5znX5g2ujzrkIU//T15KQzA==} + dependencies: + serve-static: 1.15.0 + transitivePeerDependencies: + - supports-color + dev: false + + /@react-native-community/cli-doctor@12.3.6: + resolution: {integrity: sha512-fvBDv2lTthfw4WOQKkdTop2PlE9GtfrlNnpjB818MhcdEnPjfQw5YaTUcnNEGsvGomdCs1MVRMgYXXwPSN6OvQ==} + dependencies: + '@react-native-community/cli-config': 12.3.6 + '@react-native-community/cli-platform-android': 12.3.6 + '@react-native-community/cli-platform-ios': 12.3.6 + '@react-native-community/cli-tools': 12.3.6 + chalk: 4.1.2 + command-exists: 1.2.9 + deepmerge: 4.3.1 + envinfo: 7.12.0 + execa: 5.1.1 + hermes-profile-transformer: 0.0.6 + node-stream-zip: 1.15.0 + ora: 5.4.1 + semver: 7.6.0 + strip-ansi: 5.2.0 + wcwidth: 1.0.1 + yaml: 2.4.1 + transitivePeerDependencies: + - encoding + dev: false + + /@react-native-community/cli-hermes@12.3.6: + resolution: {integrity: sha512-sNGwfOCl8OAIjWCkwuLpP8NZbuO0dhDI/2W7NeOGDzIBsf4/c4MptTrULWtGIH9okVPLSPX0NnRyGQ+mSwWyuQ==} + dependencies: + '@react-native-community/cli-platform-android': 12.3.6 + '@react-native-community/cli-tools': 12.3.6 + chalk: 4.1.2 + hermes-profile-transformer: 0.0.6 + transitivePeerDependencies: + - encoding + dev: false + + /@react-native-community/cli-platform-android@12.3.6: + resolution: {integrity: sha512-DeDDAB8lHpuGIAPXeeD9Qu2+/wDTFPo99c8uSW49L0hkmZJixzvvvffbGQAYk32H0TmaI7rzvzH+qzu7z3891g==} + dependencies: + '@react-native-community/cli-tools': 12.3.6 + chalk: 4.1.2 + execa: 5.1.1 + fast-xml-parser: 4.3.6 + glob: 7.2.3 + logkitty: 0.7.1 + transitivePeerDependencies: + - encoding + dev: false + + /@react-native-community/cli-platform-ios@12.3.6: + resolution: {integrity: sha512-3eZ0jMCkKUO58wzPWlvAPRqezVKm9EPZyaPyHbRPWU8qw7JqkvnRlWIaYDGpjCJgVW4k2hKsEursLtYKb188tg==} + dependencies: + '@react-native-community/cli-tools': 12.3.6 + chalk: 4.1.2 + execa: 5.1.1 + fast-xml-parser: 4.3.6 + glob: 7.2.3 + ora: 5.4.1 + transitivePeerDependencies: + - encoding + dev: false + + /@react-native-community/cli-plugin-metro@12.3.6: + resolution: {integrity: sha512-3jxSBQt4fkS+KtHCPSyB5auIT+KKIrPCv9Dk14FbvOaEh9erUWEm/5PZWmtboW1z7CYeNbFMeXm9fM2xwtVOpg==} + dev: false + + /@react-native-community/cli-server-api@12.3.6: + resolution: {integrity: sha512-80NIMzo8b2W+PL0Jd7NjiJW9mgaT8Y8wsIT/lh6mAvYH7mK0ecDJUYUTAAv79Tbo1iCGPAr3T295DlVtS8s4yQ==} + dependencies: + '@react-native-community/cli-debugger-ui': 12.3.6 + '@react-native-community/cli-tools': 12.3.6 + compression: 1.7.4 + connect: 3.7.0 + errorhandler: 1.5.1 + nocache: 3.0.4 + pretty-format: 26.6.2 + serve-static: 1.15.0 + ws: 7.5.9 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /@react-native-community/cli-tools@12.3.6: + resolution: {integrity: sha512-FPEvZn19UTMMXUp/piwKZSh8cMEfO8G3KDtOwo53O347GTcwNrKjgZGtLSPELBX2gr+YlzEft3CoRv2Qmo83fQ==} + dependencies: + appdirsjs: 1.2.7 + chalk: 4.1.2 + find-up: 5.0.0 + mime: 2.6.0 + node-fetch: 2.7.0 + open: 6.4.0 + ora: 5.4.1 + semver: 7.6.0 + shell-quote: 1.8.1 + sudo-prompt: 9.2.1 + transitivePeerDependencies: + - encoding + dev: false + + /@react-native-community/cli-types@12.3.6: + resolution: {integrity: sha512-xPqTgcUtZowQ8WKOkI9TLGBwH2bGggOC4d2FFaIRST3gTcjrEeGRNeR5aXCzJFIgItIft8sd7p2oKEdy90+01Q==} + dependencies: + joi: 17.12.3 + dev: false + + /@react-native-community/cli@12.3.6: + resolution: {integrity: sha512-647OSi6xBb8FbwFqX9zsJxOzu685AWtrOUWHfOkbKD+5LOpGORw+GQo0F9rWZnB68rLQyfKUZWJeaD00pGv5fw==} + engines: {node: '>=18'} + hasBin: true + dependencies: + '@react-native-community/cli-clean': 12.3.6 + '@react-native-community/cli-config': 12.3.6 + '@react-native-community/cli-debugger-ui': 12.3.6 + '@react-native-community/cli-doctor': 12.3.6 + '@react-native-community/cli-hermes': 12.3.6 + '@react-native-community/cli-plugin-metro': 12.3.6 + '@react-native-community/cli-server-api': 12.3.6 + '@react-native-community/cli-tools': 12.3.6 + '@react-native-community/cli-types': 12.3.6 + chalk: 4.1.2 + commander: 9.5.0 + deepmerge: 4.3.1 + execa: 5.1.1 + find-up: 4.1.0 + fs-extra: 8.1.0 + graceful-fs: 4.2.11 + prompts: 2.4.2 + semver: 7.6.0 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /@react-native/assets-registry@0.73.1: + resolution: {integrity: sha512-2FgAbU7uKM5SbbW9QptPPZx8N9Ke2L7bsHb+EhAanZjFZunA9PaYtyjUQ1s7HD+zDVqOQIvjkpXSv7Kejd2tqg==} + engines: {node: '>=18'} + dev: false + + /@react-native/babel-plugin-codegen@0.73.4(@babel/preset-env@7.24.4): + resolution: {integrity: sha512-XzRd8MJGo4Zc5KsphDHBYJzS1ryOHg8I2gOZDAUCGcwLFhdyGu1zBNDJYH2GFyDrInn9TzAbRIf3d4O+eltXQQ==} + engines: {node: '>=18'} + dependencies: + '@react-native/codegen': 0.73.3(@babel/preset-env@7.24.4) + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + dev: false + + /@react-native/babel-preset@0.73.21(@babel/core@7.24.3)(@babel/preset-env@7.24.4): + resolution: {integrity: sha512-WlFttNnySKQMeujN09fRmrdWqh46QyJluM5jdtDNrkl/2Hx6N4XeDUGhABvConeK95OidVO7sFFf7sNebVXogA==} + engines: {node: '>=18'} + peerDependencies: + '@babel/core': '*' + dependencies: + '@babel/core': 7.24.3 + '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.24.3) + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.24.3) + '@babel/plugin-proposal-export-default-from': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.24.3) + '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.24.3) + '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.24.3) + '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.24.3) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.24.3) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-export-default-from': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-syntax-flow': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-transform-arrow-functions': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-async-to-generator': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-block-scoping': 7.24.4(@babel/core@7.24.3) + '@babel/plugin-transform-classes': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-computed-properties': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-destructuring': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-flow-strip-types': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-function-name': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-literals': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.24.3) + '@babel/plugin-transform-parameters': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-private-methods': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-private-property-in-object': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-react-display-name': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-react-jsx': 7.23.4(@babel/core@7.24.3) + '@babel/plugin-transform-react-jsx-self': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-runtime': 7.24.3(@babel/core@7.24.3) + '@babel/plugin-transform-shorthand-properties': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-spread': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-sticky-regex': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-typescript': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-unicode-regex': 7.24.1(@babel/core@7.24.3) + '@babel/template': 7.24.0 + '@react-native/babel-plugin-codegen': 0.73.4(@babel/preset-env@7.24.4) + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.24.3) + react-refresh: 0.14.0 + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + dev: false + + /@react-native/codegen@0.73.3(@babel/preset-env@7.24.4): + resolution: {integrity: sha512-sxslCAAb8kM06vGy9Jyh4TtvjhcP36k/rvj2QE2Jdhdm61KvfafCATSIsOfc0QvnduWFcpXUPvAVyYwuv7PYDg==} + engines: {node: '>=18'} + peerDependencies: + '@babel/preset-env': ^7.1.6 + dependencies: + '@babel/parser': 7.24.1 + '@babel/preset-env': 7.24.4(@babel/core@7.24.3) + flow-parser: 0.206.0 + glob: 7.2.3 + invariant: 2.2.4 + jscodeshift: 0.14.0(@babel/preset-env@7.24.4) + mkdirp: 0.5.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@react-native/community-cli-plugin@0.73.17(@babel/core@7.24.3)(@babel/preset-env@7.24.4): + resolution: {integrity: sha512-F3PXZkcHg+1ARIr6FRQCQiB7ZAA+MQXGmq051metRscoLvgYJwj7dgC8pvgy0kexzUkHu5BNKrZeySzUft3xuQ==} + engines: {node: '>=18'} + dependencies: + '@react-native-community/cli-server-api': 12.3.6 + '@react-native-community/cli-tools': 12.3.6 + '@react-native/dev-middleware': 0.73.8 + '@react-native/metro-babel-transformer': 0.73.15(@babel/core@7.24.3)(@babel/preset-env@7.24.4) + chalk: 4.1.2 + execa: 5.1.1 + metro: 0.80.8 + metro-config: 0.80.8 + metro-core: 0.80.8 + node-fetch: 2.7.0 + readline: 1.3.0 + transitivePeerDependencies: + - '@babel/core' + - '@babel/preset-env' + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /@react-native/debugger-frontend@0.73.3: + resolution: {integrity: sha512-RgEKnWuoo54dh7gQhV7kvzKhXZEhpF9LlMdZolyhGxHsBqZ2gXdibfDlfcARFFifPIiaZ3lXuOVVa4ei+uPgTw==} + engines: {node: '>=18'} + dev: false + + /@react-native/dev-middleware@0.73.8: + resolution: {integrity: sha512-oph4NamCIxkMfUL/fYtSsE+JbGOnrlawfQ0kKtDQ5xbOjPKotKoXqrs1eGwozNKv7FfQ393stk1by9a6DyASSg==} + engines: {node: '>=18'} + dependencies: + '@isaacs/ttlcache': 1.4.1 + '@react-native/debugger-frontend': 0.73.3 + chrome-launcher: 0.15.2 + chromium-edge-launcher: 1.0.0 + connect: 3.7.0 + debug: 2.6.9 + node-fetch: 2.7.0 + open: 7.4.2 + serve-static: 1.15.0 + temp-dir: 2.0.0 + ws: 6.2.2 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false - /@parcel/watcher@2.4.1: - resolution: {integrity: sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==} - engines: {node: '>= 10.0.0'} - dependencies: - detect-libc: 1.0.3 - is-glob: 4.0.3 - micromatch: 4.0.5 - node-addon-api: 7.1.0 - optionalDependencies: - '@parcel/watcher-android-arm64': 2.4.1 - '@parcel/watcher-darwin-arm64': 2.4.1 - '@parcel/watcher-darwin-x64': 2.4.1 - '@parcel/watcher-freebsd-x64': 2.4.1 - '@parcel/watcher-linux-arm-glibc': 2.4.1 - '@parcel/watcher-linux-arm64-glibc': 2.4.1 - '@parcel/watcher-linux-arm64-musl': 2.4.1 - '@parcel/watcher-linux-x64-glibc': 2.4.1 - '@parcel/watcher-linux-x64-musl': 2.4.1 - '@parcel/watcher-win32-arm64': 2.4.1 - '@parcel/watcher-win32-ia32': 2.4.1 - '@parcel/watcher-win32-x64': 2.4.1 + /@react-native/gradle-plugin@0.73.4: + resolution: {integrity: sha512-PMDnbsZa+tD55Ug+W8CfqXiGoGneSSyrBZCMb5JfiB3AFST3Uj5e6lw8SgI/B6SKZF7lG0BhZ6YHZsRZ5MlXmg==} + engines: {node: '>=18'} dev: false - /@pkgjs/parseargs@0.11.0: - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - requiresBuild: true - dev: true - optional: true + /@react-native/js-polyfills@0.73.1: + resolution: {integrity: sha512-ewMwGcumrilnF87H4jjrnvGZEaPFCAC4ebraEK+CurDDmwST/bIicI4hrOAv+0Z0F7DEK4O4H7r8q9vH7IbN4g==} + engines: {node: '>=18'} + dev: false - /@pnpm/deps.graph-sequencer@1.0.0: - resolution: {integrity: sha512-vWWVbYYBBN/kweokmURicokyg7crzcDZo9/naziv8B8RSWrLWFpq5Xl0ro6QCQKgRmb6O78Qy9uQT+Fp79RxsA==} - engines: {node: '>=16.14'} - dev: true + /@react-native/metro-babel-transformer@0.73.15(@babel/core@7.24.3)(@babel/preset-env@7.24.4): + resolution: {integrity: sha512-LlkSGaXCz+xdxc9819plmpsl4P4gZndoFtpjN3GMBIu6f7TBV0GVbyJAU4GE8fuAWPVSVL5ArOcdkWKSbI1klw==} + engines: {node: '>=18'} + peerDependencies: + '@babel/core': '*' + dependencies: + '@babel/core': 7.24.3 + '@react-native/babel-preset': 0.73.21(@babel/core@7.24.3)(@babel/preset-env@7.24.4) + hermes-parser: 0.15.0 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + dev: false - /@polka/url@1.0.0-next.25: - resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} - dev: true + /@react-native/normalize-colors@0.73.2: + resolution: {integrity: sha512-bRBcb2T+I88aG74LMVHaKms2p/T8aQd8+BZ7LuuzXlRfog1bMWWn/C5i0HVuvW4RPtXQYgIlGiXVDy9Ir1So/w==} + dev: false + + /@react-native/virtualized-lists@0.73.4(react-native@0.73.6): + resolution: {integrity: sha512-HpmLg1FrEiDtrtAbXiwCgXFYyloK/dOIPIuWW3fsqukwJEWAiTzm1nXGJ7xPU5XTHiWZ4sKup5Ebaj8z7iyWog==} + engines: {node: '>=18'} + peerDependencies: + react-native: '*' + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react-native: 0.73.6(@babel/core@7.24.3)(@babel/preset-env@7.24.4)(react@18.2.0) + dev: false /@rollup/rollup-android-arm-eabi@4.13.0: resolution: {integrity: sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==} @@ -2438,8 +4103,44 @@ packages: dev: true optional: true + /@sideway/address@4.1.5: + resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} + dependencies: + '@hapi/hoek': 9.3.0 + dev: false + + /@sideway/formula@3.0.1: + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + dev: false + + /@sideway/pinpoint@2.0.0: + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + dev: false + /@sinclair/typebox@0.27.8: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + /@sinonjs/commons@3.0.1: + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + dependencies: + type-detect: 4.0.8 + dev: false + + /@sinonjs/fake-timers@10.3.0: + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + dependencies: + '@sinonjs/commons': 3.0.1 + dev: false + + /@sqlite.org/sqlite-wasm@3.45.2-build1: + resolution: {integrity: sha512-TeQf8rNFQna8pg95IshtpXkhdMq1iNAXllCoNrhEn18660Hbal9yxKAYv+ZfC1kjfdEXMK6V0XanfX5OT5FyMw==} + hasBin: true + dev: false + + /@types/better-sqlite3@7.6.9: + resolution: {integrity: sha512-FvktcujPDj9XKMJQWFcl2vVl7OdRIqsSRX9b0acWwTmwLK9CF2eqo/FRcmMLNpugKoX/avA6pb7TorDLmpgTnQ==} + dependencies: + '@types/node': 20.11.30 dev: true /@types/dedent@0.7.0: @@ -2470,19 +4171,16 @@ packages: /@types/istanbul-lib-coverage@2.0.6: resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - dev: true /@types/istanbul-lib-report@3.0.3: resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} dependencies: '@types/istanbul-lib-coverage': 2.0.6 - dev: true /@types/istanbul-reports@3.0.4: resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} dependencies: '@types/istanbul-lib-report': 3.0.3 - dev: true /@types/js-yaml@3.12.5: resolution: {integrity: sha512-JCcp6J0GV66Y4ZMDAQCXot4xprYB+Zfd3meK9+INSJeVZwJmHAW30BBEEkPzXswMXuiyReUGOP3GxrADc9wPww==} @@ -2533,7 +4231,6 @@ packages: resolution: {integrity: sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==} dependencies: undici-types: 5.26.5 - dev: true /@types/normalize-package-data@2.4.4: resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -2543,13 +4240,19 @@ packages: resolution: {integrity: sha512-ZkC5IUqqIFPXx3ASTTybTzmQdwHwe2C0u3eL75ldQ6T9E9IWFJodn6hIfbZGab73DfyiHN4Xw15gNxUq2FbvBA==} dev: true + /@types/readable-stream@4.0.11: + resolution: {integrity: sha512-R3eUMUTTKoIoaz7UpYLxvZCrOmCRPRbAmoDDHKcimTEySltaJhF8hLzj4+EzyDifiX5eK6oDQGSfmNnXjxZzYQ==} + dependencies: + '@types/node': 20.11.30 + safe-buffer: 5.1.2 + dev: false + /@types/semver@7.5.8: resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} dev: true /@types/stack-utils@2.0.3: resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} - dev: true /@types/tar@6.1.11: resolution: {integrity: sha512-ThA1WD8aDdVU4VLuyq5NEqriwXErF5gEIJeyT6gHBWU7JtSmW2a5qjNv3/vR82O20mW+1vhmeZJfBQPT3HCugg==} @@ -2570,13 +4273,17 @@ packages: /@types/yargs-parser@21.0.3: resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - dev: true + + /@types/yargs@15.0.19: + resolution: {integrity: sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==} + dependencies: + '@types/yargs-parser': 21.0.3 + dev: false /@types/yargs@17.0.32: resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} dependencies: '@types/yargs-parser': 21.0.3 - dev: true /@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.3.1)(eslint@8.57.0)(typescript@5.4.3): resolution: {integrity: sha512-STEDMVQGww5lhCuNXVSQfbfuNII5E08QWkvAw5Qwf+bj2WT+JkG1uc+5/vXA3AOYMDHVOSpL+9rcbEUiHIm2dw==} @@ -2906,6 +4613,21 @@ packages: - supports-color dev: true + /abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + dependencies: + event-target-shim: 5.0.1 + dev: false + + /accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + dev: false + /acorn-jsx@5.3.2(acorn@8.11.3): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -2923,7 +4645,15 @@ packages: resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} engines: {node: '>=0.4.0'} hasBin: true - dev: true + + /agent-base@7.1.1: + resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} + engines: {node: '>= 14'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -2943,15 +4673,31 @@ packages: uri-js: 4.4.1 dev: true + /anser@1.4.10: + resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} + dev: false + /ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} dev: true + /ansi-fragments@0.2.1: + resolution: {integrity: sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==} + dependencies: + colorette: 1.4.0 + slice-ansi: 2.1.0 + strip-ansi: 5.2.0 + dev: false + + /ansi-regex@4.1.1: + resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} + engines: {node: '>=6'} + dev: false + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - dev: true /ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} @@ -2963,19 +4709,16 @@ packages: engines: {node: '>=4'} dependencies: color-convert: 1.9.3 - dev: true /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} dependencies: color-convert: 2.0.1 - dev: true /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} - dev: true /ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} @@ -2993,18 +4736,19 @@ packages: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - dev: true - optional: true /app-module-path@2.2.0: resolution: {integrity: sha512-gkco+qxENJV+8vFcDiiFhuoSvRXb2a/QPqpSoWhVz829VNJfOTnELbBmPmNKFxf3xdNnw4DWCkzkDaavcX/1YQ==} dev: true + /appdirsjs@1.2.7: + resolution: {integrity: sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==} + dev: false + /argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: sprintf-js: 1.0.3 - dev: true /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -3095,6 +4839,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + dev: false + /assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} dev: true @@ -3116,6 +4864,13 @@ packages: tslib: 2.6.2 dev: true + /ast-types@0.15.2: + resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} + engines: {node: '>=4'} + dependencies: + tslib: 2.6.2 + dev: false + /ast-types@0.16.1: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} @@ -3123,6 +4878,15 @@ packages: tslib: 2.6.2 dev: true + /astral-regex@1.0.0: + resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==} + engines: {node: '>=4'} + dev: false + + /async-limiter@1.0.1: + resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} + dev: false + /autolinker@0.28.1: resolution: {integrity: sha512-zQAFO1Dlsn69eXaO6+7YZc+v84aquQKbwpzCE3L0stj56ERn9hutFxPopViLjo9G+rWwjozRhgS5KJ25Xy19cQ==} dependencies: @@ -3142,7 +4906,6 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - dev: true /babel-plugin-annotate-pure-calls@0.4.0(@babel/core@7.24.3): resolution: {integrity: sha512-oi4M/PWUJOU9ZyRGoPTfPMqdyMp06jbJAomd3RcyYuzUtBOddv98BqLm96Lucpi2QFoQHkdGQt0ACvw7VzVEQA==} @@ -3152,13 +4915,55 @@ packages: '@babel/core': 7.24.3 dev: true + /babel-plugin-polyfill-corejs2@0.4.10(@babel/core@7.24.3): + resolution: {integrity: sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/compat-data': 7.24.1 + '@babel/core': 7.24.3 + '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.3) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: false + + /babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.3): + resolution: {integrity: sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.3) + core-js-compat: 3.36.1 + transitivePeerDependencies: + - supports-color + dev: false + + /babel-plugin-polyfill-regenerator@0.6.1(@babel/core@7.24.3): + resolution: {integrity: sha512-JfTApdE++cgcTWjsiCQlLyFBMbTUft9ja17saCc93lgV33h4tuCVj7tlvu//qpLwaG+3yEz7/KhahGrUMkVq9g==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.3) + transitivePeerDependencies: + - supports-color + dev: false + + /babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.24.3): + resolution: {integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==} + dependencies: + '@babel/plugin-syntax-flow': 7.24.1(@babel/core@7.24.3) + transitivePeerDependencies: + - '@babel/core' + dev: false + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - dev: true /better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} @@ -3167,6 +4972,14 @@ packages: is-windows: 1.0.2 dev: true + /better-sqlite3@9.5.0: + resolution: {integrity: sha512-01qVcM4gPNwE+PX7ARNiHINwzVuD6nx0gdldaAAcu+MrzyIAukQ31ZDKEpzRO/CNA9sHpxoTZ8rdjoyAin4dyg==} + requiresBuild: true + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.2 + dev: false + /binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -3174,20 +4987,33 @@ packages: dev: true optional: true + /bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + dependencies: + file-uri-to-path: 1.0.0 + dev: false + /bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} dependencies: buffer: 5.7.1 inherits: 2.0.4 readable-stream: 3.6.2 - dev: true + + /bl@6.0.12: + resolution: {integrity: sha512-EnEYHilP93oaOa2MnmNEjAcovPS3JlQZOyzGXi3EyEpPhm9qWvdDp7BmAVEVusGzp8LlwQK56Av+OkDoRjzE0w==} + dependencies: + '@types/readable-stream': 4.0.11 + buffer: 6.0.3 + inherits: 2.0.4 + readable-stream: 4.5.2 + dev: false /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - dev: true /brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} @@ -3216,18 +5042,32 @@ packages: electron-to-chromium: 1.4.714 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.23.0) - dev: true + + /bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + dependencies: + node-int64: 0.4.0 + dev: false + + /buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + dev: false /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true /buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - dev: true + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false /builtin-modules@1.1.1: resolution: {integrity: sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==} @@ -3241,6 +5081,11 @@ packages: '@types/ws': 8.5.10 dev: true + /bytes@3.0.0: + resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} + engines: {node: '>= 0.8'} + dev: false + /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -3257,6 +5102,25 @@ packages: set-function-length: 1.2.1 dev: true + /caller-callsite@2.0.0: + resolution: {integrity: sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==} + engines: {node: '>=4'} + dependencies: + callsites: 2.0.0 + dev: false + + /caller-path@2.0.0: + resolution: {integrity: sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==} + engines: {node: '>=4'} + dependencies: + caller-callsite: 2.0.0 + dev: false + + /callsites@2.0.0: + resolution: {integrity: sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==} + engines: {node: '>=4'} + dev: false + /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -3274,11 +5138,14 @@ packages: /camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} - dev: true + + /camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: false /caniuse-lite@1.0.30001599: resolution: {integrity: sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==} - dev: true /chai@4.4.1: resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} @@ -3300,7 +5167,6 @@ packages: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 - dev: true /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -3308,7 +5174,6 @@ packages: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: true /character-entities-legacy@1.1.4: resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} @@ -3349,27 +5214,58 @@ packages: dev: true optional: true + /chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + dev: false + /chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} dev: true + /chrome-launcher@0.15.2: + resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} + engines: {node: '>=12.13.0'} + hasBin: true + dependencies: + '@types/node': 20.11.30 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + transitivePeerDependencies: + - supports-color + dev: false + + /chromium-edge-launcher@1.0.0: + resolution: {integrity: sha512-pgtgjNKZ7i5U++1g1PWv75umkHvhVTDOQIZ+sjeUX9483S7Y6MUvO0lrd7ShGlQlFHMN4SwKTCq/X8hWrbv2KA==} + dependencies: + '@types/node': 20.11.30 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + mkdirp: 1.0.4 + rimraf: 3.0.2 + transitivePeerDependencies: + - supports-color + dev: false + + /ci-info@2.0.0: + resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + dev: false + /ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} - dev: true /cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} dependencies: restore-cursor: 3.1.0 - dev: true /cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - dev: true /cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} @@ -3377,7 +5273,6 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 6.2.0 - dev: true /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} @@ -3386,7 +5281,6 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - dev: true /clone-deep@4.0.1: resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} @@ -3395,12 +5289,10 @@ packages: is-plain-object: 2.0.4 kind-of: 6.0.3 shallow-clone: 3.0.1 - dev: true /clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} - dev: true /cluster-key-slot@1.1.2: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} @@ -3411,22 +5303,26 @@ packages: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 - dev: true /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 - dev: true /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true + + /colorette@1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + dev: false + + /command-exists@1.2.9: + resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} + dev: false /commander@10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} @@ -3435,7 +5331,6 @@ packages: /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - dev: true /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} @@ -3447,13 +5342,38 @@ packages: engines: {node: '>= 10'} dev: true + /commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + dev: false + /commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} - dev: true + + /compressible@2.0.18: + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + + /compression@1.7.4: + resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==} + engines: {node: '>= 0.8.0'} + dependencies: + accepts: 1.3.8 + bytes: 3.0.0 + compressible: 2.0.18 + debug: 2.6.9 + on-headers: 1.0.2 + safe-buffer: 5.1.2 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + dev: false /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true /concat-stream@1.6.2: resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} @@ -3471,13 +5391,39 @@ packages: source-map: 0.6.1 dev: true + /connect@3.7.0: + resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} + engines: {node: '>= 0.10.0'} + dependencies: + debug: 2.6.9 + finalhandler: 1.1.2 + parseurl: 1.3.3 + utils-merge: 1.0.1 + transitivePeerDependencies: + - supports-color + dev: false + /convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true + + /core-js-compat@3.36.1: + resolution: {integrity: sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==} + dependencies: + browserslist: 4.23.0 + dev: false /core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - dev: true + + /cosmiconfig@5.2.1: + resolution: {integrity: sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==} + engines: {node: '>=4'} + dependencies: + import-fresh: 2.0.0 + is-directory: 0.3.1 + js-yaml: 3.14.1 + parse-json: 4.0.0 + dev: false /cross-spawn@5.1.0: resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} @@ -3494,7 +5440,6 @@ packages: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: true /csv-generate@3.4.3: resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==} @@ -3522,6 +5467,21 @@ packages: resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} dev: true + /dayjs@1.11.10: + resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} + dev: false + + /debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.0.0 + dev: false + /debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -3543,7 +5503,6 @@ packages: optional: true dependencies: ms: 2.1.2 - dev: true /decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} @@ -3556,7 +5515,13 @@ packages: /decamelize@1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} - dev: true + + /decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dependencies: + mimic-response: 3.1.0 + dev: false /dedent@1.5.1: resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} @@ -3577,17 +5542,20 @@ packages: /deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} - dev: true /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true + /deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + dev: false + /defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} dependencies: clone: 1.0.4 - dev: true /define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} @@ -3598,6 +5566,11 @@ packages: gopd: 1.0.1 dev: true + /define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + dev: false + /define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -3607,10 +5580,18 @@ packages: object-keys: 1.1.1 dev: true + /denodeify@1.2.1: + resolution: {integrity: sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==} + dev: false + /denque@2.1.0: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} - dev: true + + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dev: false /dependency-tree@10.0.9: resolution: {integrity: sha512-dwc59FRIsht+HfnTVM0BCjJaEWxdq2YAvEDy4/Hn6CwS3CBWMtFnL3aZGAkQn3XCYxk/YcTDE4jX2Q7bFTwCjA==} @@ -3625,6 +5606,20 @@ packages: - supports-color dev: true + /deprecated-react-native-prop-types@5.0.0: + resolution: {integrity: sha512-cIK8KYiiGVOFsKdPMmm1L3tA/Gl+JopXL6F5+C7x39MyPsQYnP57Im/D6bNUzcborD7fcMwiwZqcBdBXXZucYQ==} + engines: {node: '>=18'} + dependencies: + '@react-native/normalize-colors': 0.73.2 + invariant: 2.2.4 + prop-types: 15.8.1 + dev: false + + /destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dev: false + /detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -3639,7 +5634,6 @@ packages: /detect-libc@2.0.3: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} - dev: true /detective-amd@5.0.2: resolution: {integrity: sha512-XFd/VEQ76HSpym80zxM68ieB77unNuoMwopU2TFT/ErUk5n4KvUTwW4beafAVUugrjV48l4BmmR0rh2MglBaiA==} @@ -3770,18 +5764,37 @@ packages: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true + /ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + dev: false + /electron-to-chromium@1.4.714: resolution: {integrity: sha512-OfnVHt+nMRH9Ua5koH/2gKlCAXbG+u1yXwLKyBVqNboBV34ZTwb846RUe8K5mtE1uhz0BXoMarZ13JCQr+sBtQ==} - dev: true /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} dev: true + /encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + dev: false + + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: false + /enhanced-resolve@5.15.0: resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==} engines: {node: '>=10.13.0'} @@ -3803,11 +5816,30 @@ packages: engines: {node: '>=0.12'} dev: true + /envinfo@7.12.0: + resolution: {integrity: sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==} + engines: {node: '>=4'} + hasBin: true + dev: false + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: is-arrayish: 0.2.1 - dev: true + + /error-stack-parser@2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + dependencies: + stackframe: 1.3.4 + dev: false + + /errorhandler@1.5.1: + resolution: {integrity: sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==} + engines: {node: '>= 0.8'} + dependencies: + accepts: 1.3.8 + escape-html: 1.0.3 + dev: false /es-abstract@1.22.4: resolution: {integrity: sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==} @@ -3961,22 +5993,22 @@ packages: /escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} - dev: true + + /escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + dev: false /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} - dev: true /escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} - dev: true /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - dev: true /escodegen@2.1.0: resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} @@ -4237,7 +6269,6 @@ packages: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - dev: true /esquery@1.5.0: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} @@ -4267,7 +6298,36 @@ packages: /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - dev: true + + /etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + dev: false + + /event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + dev: false + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: false + + /execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: false /execa@8.0.1: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} @@ -4291,6 +6351,11 @@ packages: fill-range: 2.2.4 dev: true + /expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + dev: false + /expect@29.7.0: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4362,12 +6427,25 @@ packages: fast-decode-uri-component: 1.0.1 dev: false + /fast-xml-parser@4.3.6: + resolution: {integrity: sha512-M2SovcRxD4+vC493Uc2GZVcZaj66CCJhWurC4viynVSTvrpErCShNcDz1lAho6n9REQKvL/ll4A4/fw6Y9z8nw==} + hasBin: true + dependencies: + strnum: 1.0.5 + dev: false + /fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} dependencies: reusify: 1.0.4 dev: true + /fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + dependencies: + bser: 2.1.1 + dev: false + /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -4375,6 +6453,10 @@ packages: flat-cache: 3.2.0 dev: true + /file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + dev: false + /filing-cabinet@4.1.6: resolution: {integrity: sha512-C+HZbuQTER36sKzGtUhrAPAoK6+/PrrUhYDBQEh3kBRdsyEhkLbp1ML8S0+6e6gCUrUlid+XmubxJrhvL2g/Zw==} engines: {node: '>=14'} @@ -4412,6 +6494,21 @@ packages: dependencies: to-regex-range: 5.0.1 + /finalhandler@1.1.2: + resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} + engines: {node: '>= 0.8'} + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: false + /find-cache-dir@2.1.0: resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==} engines: {node: '>=6'} @@ -4419,7 +6516,6 @@ packages: commondir: 1.0.1 make-dir: 2.1.0 pkg-dir: 3.0.0 - dev: true /find-my-way-ts@0.1.1: resolution: {integrity: sha512-nXUdq29JRQ1tYa1/n+DHTVChMARJHz+gi7sDZibwQukzHP7Hrr6s+sxKbaIM8xB3LzhSBJy5yLb0JhIUmHmOiA==} @@ -4432,7 +6528,6 @@ packages: engines: {node: '>=6'} dependencies: locate-path: 3.0.0 - dev: true /find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} @@ -4440,7 +6535,6 @@ packages: dependencies: locate-path: 5.0.0 path-exists: 4.0.0 - dev: true /find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} @@ -4448,7 +6542,6 @@ packages: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - dev: true /find-yarn-workspace-root2@1.2.16: resolution: {integrity: sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==} @@ -4470,10 +6563,18 @@ packages: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} dev: true + /flow-enums-runtime@0.0.6: + resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} + dev: false + + /flow-parser@0.206.0: + resolution: {integrity: sha512-HVzoK3r6Vsg+lKvlIZzaWNBVai+FXTX1wdYhz/wVlH13tb/gOdLXmlTqy6odmTBhT5UoWUbq0k8263Qhr9d88w==} + engines: {node: '>=0.4.0'} + dev: false + /flow-parser@0.231.0: resolution: {integrity: sha512-WVzuqwq7ZnvBceCG0DGeTQebZE+iIU0mlk5PmJgYj9DDrt+0isGC2m1ezW9vxL4V+HERJJo9ExppOnwKH2op6Q==} engines: {node: '>=0.4.0'} - dev: true /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -4498,6 +6599,15 @@ packages: resolution: {integrity: sha512-EkV/l6oHaf/w/DlVc5UiqLibqTV1S+idiDdcWQ+UjnLLflL9pZG28ebJfPLor8ifoL8NgEFDIo9fOvHyiSCrJQ==} dev: true + /fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + dev: false + + /fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + dev: false + /fs-extra@11.1.1: resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} engines: {node: '>=14.14'} @@ -4523,7 +6633,6 @@ packages: graceful-fs: 4.2.11 jsonfile: 4.0.0 universalify: 0.1.2 - dev: true /fs-minipass@2.1.0: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} @@ -4538,7 +6647,6 @@ packages: /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true /fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} @@ -4553,12 +6661,10 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true - dev: true optional: true /function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: true /function.prototype.name@1.1.6: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} @@ -4574,10 +6680,15 @@ packages: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true + /generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + dependencies: + is-property: 1.0.2 + dev: false + /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - dev: true /get-amd-module-type@5.0.1: resolution: {integrity: sha512-jb65zDeHyDjFR1loOVk0HQGM5WNwoGB8aLWy3LKCieMKol0/ProHkhO2X1JxojuN10vbz1qNn09MJ7tNp7qMzw==} @@ -4590,7 +6701,6 @@ packages: /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - dev: true /get-func-name@2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} @@ -4611,6 +6721,11 @@ packages: resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} dev: true + /get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: false + /get-stream@8.0.1: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} @@ -4631,6 +6746,10 @@ packages: resolve-pkg-maps: 1.0.0 dev: true + /github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + dev: false + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -4666,12 +6785,10 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - dev: true /globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} @@ -4715,7 +6832,6 @@ packages: /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true /grapheme-splitter@1.0.4: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} @@ -4765,12 +6881,10 @@ packages: /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} - dev: true /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - dev: true /has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} @@ -4800,7 +6914,33 @@ packages: engines: {node: '>= 0.4'} dependencies: function-bind: 1.1.2 - dev: true + + /hermes-estree@0.15.0: + resolution: {integrity: sha512-lLYvAd+6BnOqWdnNbP/Q8xfl8LOGw4wVjfrNd9Gt8eoFzhNBRVD95n4l2ksfMVOoxuVyegs85g83KS9QOsxbVQ==} + dev: false + + /hermes-estree@0.20.1: + resolution: {integrity: sha512-SQpZK4BzR48kuOg0v4pb3EAGNclzIlqMj3Opu/mu7bbAoFw6oig6cEt/RAi0zTFW/iW6Iz9X9ggGuZTAZ/yZHg==} + dev: false + + /hermes-parser@0.15.0: + resolution: {integrity: sha512-Q1uks5rjZlE9RjMMjSUCkGrEIPI5pKJILeCtK1VmTj7U4pf3wVPoo+cxfu+s4cBAPy2JzikIIdCZgBoR6x7U1Q==} + dependencies: + hermes-estree: 0.15.0 + dev: false + + /hermes-parser@0.20.1: + resolution: {integrity: sha512-BL5P83cwCogI8D7rrDCgsFY0tdYUtmFP9XaXtl2IQjC+2Xo+4okjfXintlTxcIwl4qeGddEl28Z11kbVIw0aNA==} + dependencies: + hermes-estree: 0.20.1 + dev: false + + /hermes-profile-transformer@0.0.6: + resolution: {integrity: sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==} + engines: {node: '>=8'} + dependencies: + source-map: 0.7.4 + dev: false /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -4810,10 +6950,46 @@ packages: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} dev: true + /http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + dev: false + + /http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.1 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /https-proxy-agent@7.0.4: + resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.1 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + /human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} dev: true + /human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: false + /human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} @@ -4826,15 +7002,37 @@ packages: safer-buffer: 2.1.2 dev: true + /iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: false + /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: true /ignore@5.3.1: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} dev: true + /image-size@1.1.1: + resolution: {integrity: sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==} + engines: {node: '>=16.x'} + hasBin: true + dependencies: + queue: 6.0.2 + dev: false + + /import-fresh@2.0.0: + resolution: {integrity: sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==} + engines: {node: '>=4'} + dependencies: + caller-path: 2.0.0 + resolve-from: 3.0.0 + dev: false + /import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -4846,7 +7044,6 @@ packages: /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - dev: true /indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} @@ -4858,15 +7055,12 @@ packages: dependencies: once: 1.4.0 wrappy: 1.0.2 - dev: true /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true /ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - dev: true /ini@4.1.2: resolution: {integrity: sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==} @@ -4882,6 +7076,12 @@ packages: side-channel: 1.0.5 dev: true + /invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + dependencies: + loose-envify: 1.4.0 + dev: false + /io-ts-extra@0.11.6: resolution: {integrity: sha512-rTsvx3W5B2nx7p/eGf+OsEaBTmjSjLzxBDEiweCjwqIL9ZN6CZjG7hFK8zyGJyM0I2uCsRU4uYUhaTgg2SKHkQ==} dependencies: @@ -4935,7 +7135,6 @@ packages: /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: true /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} @@ -4973,7 +7172,6 @@ packages: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} dependencies: hasown: 2.0.1 - dev: true /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} @@ -4986,6 +7184,17 @@ packages: resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} dev: true + /is-directory@0.3.1: + resolution: {integrity: sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==} + engines: {node: '>=0.10.0'} + dev: false + + /is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + dev: false + /is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} @@ -5002,10 +7211,14 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + /is-fullwidth-code-point@2.0.0: + resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} + engines: {node: '>=4'} + dev: false + /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - dev: true /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} @@ -5020,7 +7233,6 @@ packages: /is-interactive@1.0.0: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} - dev: true /is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} @@ -5071,7 +7283,10 @@ packages: engines: {node: '>=0.10.0'} dependencies: isobject: 3.0.1 - dev: true + + /is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + dev: false /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} @@ -5097,6 +7312,11 @@ packages: call-bind: 1.0.7 dev: true + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: false + /is-stream@3.0.0: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -5133,7 +7353,6 @@ packages: /is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} - dev: true /is-url-superb@4.0.0: resolution: {integrity: sha512-GI+WjezhPPcbM+tqE9LnmsY5qqjwHzTvjJ36wxYX5ujNXefSUJ/T17r5bqDV8yLhcgB59KTPNOc9O9cmHTPWsA==} @@ -5155,9 +7374,20 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-wsl@1.1.0: + resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} + engines: {node: '>=4'} + dev: false + + /is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + dependencies: + is-docker: 2.2.1 + dev: false + /isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - dev: true /isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} @@ -5165,7 +7395,6 @@ packages: /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true /isobject@2.1.0: resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} @@ -5177,7 +7406,6 @@ packages: /isobject@3.0.1: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} - dev: true /isows@1.0.4(ws@8.16.0): resolution: {integrity: sha512-hEzjY+x9u9hPmBom9IIAqdJCwNLax+xrPb51vEPpERoFlIxgmZcHzsT5jKG06nvInKOBGvReAVz80Umed5CczQ==} @@ -5239,10 +7467,21 @@ packages: pretty-format: 29.7.0 dev: true + /jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.11.30 + jest-mock: 29.7.0 + jest-util: 29.7.0 + dev: false + /jest-get-type@29.6.3: resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true /jest-matcher-utils@29.7.0: resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} @@ -5267,7 +7506,15 @@ packages: pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.6 - dev: true + + /jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.11.30 + jest-util: 29.7.0 + dev: false /jest-util@29.7.0: resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} @@ -5279,11 +7526,45 @@ packages: ci-info: 3.9.0 graceful-fs: 4.2.11 picomatch: 2.3.1 - dev: true + + /jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + dev: false + + /jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@types/node': 20.11.30 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: false + + /joi@17.12.3: + resolution: {integrity: sha512-2RRziagf555owrm9IRVtdKynOBeITiDpuZqIpgwqXShPncPKNiRQoiGsl/T8SQdq+8ugRzH2LqY67irr2y/d+g==} + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.5 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + dev: false + + /js-md4@0.3.2: + resolution: {integrity: sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==} + dev: false /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true /js-tokens@8.0.3: resolution: {integrity: sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==} @@ -5295,7 +7576,6 @@ packages: dependencies: argparse: 1.0.10 esprima: 4.0.1 - dev: true /js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} @@ -5304,6 +7584,44 @@ packages: argparse: 2.0.1 dev: true + /jsc-android@250231.0.0: + resolution: {integrity: sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw==} + dev: false + + /jsc-safe-url@0.2.4: + resolution: {integrity: sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==} + dev: false + + /jscodeshift@0.14.0(@babel/preset-env@7.24.4): + resolution: {integrity: sha512-7eCC1knD7bLUPuSCwXsMZUH51O8jIcoVyKtI6P0XM0IVzlGjckPy3FIwQlorzbN0Sg79oK+RlohN32Mqf/lrYA==} + hasBin: true + peerDependencies: + '@babel/preset-env': ^7.1.6 + dependencies: + '@babel/core': 7.24.3 + '@babel/parser': 7.24.1 + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.24.3) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.24.3) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.24.3) + '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.3) + '@babel/preset-env': 7.24.4(@babel/core@7.24.3) + '@babel/preset-flow': 7.24.1(@babel/core@7.24.3) + '@babel/preset-typescript': 7.24.1(@babel/core@7.24.3) + '@babel/register': 7.23.7(@babel/core@7.24.3) + babel-core: 7.0.0-bridge.0(@babel/core@7.24.3) + chalk: 4.1.2 + flow-parser: 0.231.0 + graceful-fs: 4.2.11 + micromatch: 4.0.5 + neo-async: 2.6.2 + node-dir: 0.1.17 + recast: 0.21.5 + temp: 0.8.4 + write-file-atomic: 2.4.3 + transitivePeerDependencies: + - supports-color + dev: false + /jscodeshift@0.15.2: resolution: {integrity: sha512-FquR7Okgmc4Sd0aEDwqho3rEiKR3BdvuG9jfdHjLJ6JQoWSMpavug3AoIfnfWhxFlf+5pzQh8qjqz0DWFrNQzA==} hasBin: true @@ -5337,16 +7655,24 @@ packages: - supports-color dev: true + /jsesc@0.5.0: + resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} + hasBin: true + dev: false + /jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} hasBin: true - dev: true /json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} dev: true + /json-parse-better-errors@1.0.2: + resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} + dev: false + /json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} dev: true @@ -5374,7 +7700,6 @@ packages: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true - dev: true /jsonc-parser@3.2.1: resolution: {integrity: sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==} @@ -5384,7 +7709,6 @@ packages: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} optionalDependencies: graceful-fs: 4.2.11 - dev: true /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} @@ -5394,6 +7718,52 @@ packages: graceful-fs: 4.2.11 dev: true + /jsonwebtoken@9.0.2: + resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + engines: {node: '>=12', npm: '>=6'} + dependencies: + jws: 3.2.2 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.6.0 + dev: false + + /jwa@1.4.1: + resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + dev: false + + /jwa@2.0.0: + resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==} + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + dev: false + + /jws@3.2.2: + resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + dependencies: + jwa: 1.4.1 + safe-buffer: 5.2.1 + dev: false + + /jws@4.0.0: + resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} + dependencies: + jwa: 2.0.0 + safe-buffer: 5.2.1 + dev: false + /keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} dependencies: @@ -5415,7 +7785,11 @@ packages: /kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - dev: true + + /kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + dev: false /kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} @@ -5429,6 +7803,11 @@ packages: set-getter: 0.1.1 dev: true + /leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + dev: false + /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -5437,6 +7816,15 @@ packages: type-check: 0.4.0 dev: true + /lighthouse-logger@1.4.2: + resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==} + dependencies: + debug: 2.6.9 + marky: 1.2.5 + transitivePeerDependencies: + - supports-color + dev: false + /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true @@ -5494,38 +7882,67 @@ packages: dependencies: p-locate: 3.0.0 path-exists: 3.0.0 - dev: true /locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} dependencies: p-locate: 4.1.0 - dev: true /locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} dependencies: p-locate: 5.0.0 - dev: true /lodash._reinterpolate@3.0.0: resolution: {integrity: sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==} dev: true + /lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + dev: false + /lodash.defaults@4.2.0: resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} dev: true + /lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + dev: false + /lodash.isarguments@3.1.0: resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} dev: true + /lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + dev: false + + /lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + dev: false + + /lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + dev: false + + /lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + dev: false + + /lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + dev: false + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + dev: false + /lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} dev: true @@ -5543,6 +7960,10 @@ packages: lodash._reinterpolate: 3.0.0 dev: true + /lodash.throttle@4.1.1: + resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} + dev: false + /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true @@ -5553,7 +7974,26 @@ packages: dependencies: chalk: 4.1.2 is-unicode-supported: 0.1.0 - dev: true + + /logkitty@0.7.1: + resolution: {integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==} + hasBin: true + dependencies: + ansi-fragments: 0.2.1 + dayjs: 1.11.10 + yargs: 15.4.1 + dev: false + + /long@5.2.3: + resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} + dev: false + + /loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + dependencies: + js-tokens: 4.0.0 + dev: false /loupe@2.3.7: resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} @@ -5577,14 +8017,22 @@ packages: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: yallist: 3.1.1 - dev: true /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} dependencies: yallist: 4.0.0 - dev: true + + /lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + dev: false + + /lru-cache@8.0.5: + resolution: {integrity: sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==} + engines: {node: '>=16.14'} + dev: false /madge@6.1.0(typescript@5.4.3): resolution: {integrity: sha512-irWhT5RpFOc6lkzGHKLihonCVgM0YtfNUh4IrFeW3EqHpnt/JHUG3z26j8PeJEktCGB4tmGOOOJi1Rl/ACWucQ==} @@ -5644,7 +8092,6 @@ packages: dependencies: pify: 4.0.1 semver: 5.7.2 - dev: true /make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} @@ -5653,6 +8100,12 @@ packages: semver: 7.6.0 dev: true + /makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + dependencies: + tmpl: 1.0.5 + dev: false + /map-obj@1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} @@ -5668,6 +8121,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /marky@1.2.5: + resolution: {integrity: sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==} + dev: false + /math-random@1.0.4: resolution: {integrity: sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==} dev: true @@ -5682,37 +8139,251 @@ packages: unist-util-stringify-position: 2.0.3 transitivePeerDependencies: - supports-color - dev: true - - /mdast-util-to-string@2.0.0: - resolution: {integrity: sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==} - dev: true + dev: true + + /mdast-util-to-string@2.0.0: + resolution: {integrity: sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==} + dev: true + + /memoize-one@5.2.1: + resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} + dev: false + + /meow@6.1.1: + resolution: {integrity: sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==} + engines: {node: '>=8'} + dependencies: + '@types/minimist': 1.2.5 + camelcase-keys: 6.2.2 + decamelize-keys: 1.1.1 + hard-rejection: 2.1.0 + minimist-options: 4.1.0 + normalize-package-data: 2.5.0 + read-pkg-up: 7.0.1 + redent: 3.0.0 + trim-newlines: 3.0.1 + type-fest: 0.13.1 + yargs-parser: 18.1.3 + dev: true + + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /metro-babel-transformer@0.80.8: + resolution: {integrity: sha512-TTzNwRZb2xxyv4J/+yqgtDAP2qVqH3sahsnFu6Xv4SkLqzrivtlnyUbaeTdJ9JjtADJUEjCbgbFgUVafrXdR9Q==} + engines: {node: '>=18'} + dependencies: + '@babel/core': 7.24.3 + hermes-parser: 0.20.1 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + dev: false + + /metro-cache-key@0.80.8: + resolution: {integrity: sha512-qWKzxrLsRQK5m3oH8ePecqCc+7PEhR03cJE6Z6AxAj0idi99dHOSitTmY0dclXVB9vP2tQIAE8uTd8xkYGk8fA==} + engines: {node: '>=18'} + dev: false + + /metro-cache@0.80.8: + resolution: {integrity: sha512-5svz+89wSyLo7BxdiPDlwDTgcB9kwhNMfNhiBZPNQQs1vLFXxOkILwQiV5F2EwYT9DEr6OPZ0hnJkZfRQ8lDYQ==} + engines: {node: '>=18'} + dependencies: + metro-core: 0.80.8 + rimraf: 3.0.2 + dev: false + + /metro-config@0.80.8: + resolution: {integrity: sha512-VGQJpfJawtwRzGzGXVUoohpIkB0iPom4DmSbAppKfumdhtLA8uVeEPp2GM61kL9hRvdbMhdWA7T+hZFDlo4mJA==} + engines: {node: '>=18'} + dependencies: + connect: 3.7.0 + cosmiconfig: 5.2.1 + jest-validate: 29.7.0 + metro: 0.80.8 + metro-cache: 0.80.8 + metro-core: 0.80.8 + metro-runtime: 0.80.8 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /metro-core@0.80.8: + resolution: {integrity: sha512-g6lud55TXeISRTleW6SHuPFZHtYrpwNqbyFIVd9j9Ofrb5IReiHp9Zl8xkAfZQp8v6ZVgyXD7c130QTsCz+vBw==} + engines: {node: '>=18'} + dependencies: + lodash.throttle: 4.1.1 + metro-resolver: 0.80.8 + dev: false + + /metro-file-map@0.80.8: + resolution: {integrity: sha512-eQXMFM9ogTfDs2POq7DT2dnG7rayZcoEgRbHPXvhUWkVwiKkro2ngcBE++ck/7A36Cj5Ljo79SOkYwHaWUDYDw==} + engines: {node: '>=18'} + dependencies: + anymatch: 3.1.3 + debug: 2.6.9 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + invariant: 2.2.4 + jest-worker: 29.7.0 + micromatch: 4.0.5 + node-abort-controller: 3.1.1 + nullthrows: 1.1.1 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + transitivePeerDependencies: + - supports-color + dev: false + + /metro-minify-terser@0.80.8: + resolution: {integrity: sha512-y8sUFjVvdeUIINDuW1sejnIjkZfEF+7SmQo0EIpYbWmwh+kq/WMj74yVaBWuqNjirmUp1YNfi3alT67wlbBWBQ==} + engines: {node: '>=18'} + dependencies: + terser: 5.30.3 + dev: false + + /metro-resolver@0.80.8: + resolution: {integrity: sha512-JdtoJkP27GGoZ2HJlEsxs+zO7jnDUCRrmwXJozTlIuzLHMRrxgIRRby9fTCbMhaxq+iA9c+wzm3iFb4NhPmLbQ==} + engines: {node: '>=18'} + dev: false + + /metro-runtime@0.80.8: + resolution: {integrity: sha512-2oScjfv6Yb79PelU1+p8SVrCMW9ZjgEiipxq7jMRn8mbbtWzyv3g8Mkwr+KwOoDFI/61hYPUbY8cUnu278+x1g==} + engines: {node: '>=18'} + dependencies: + '@babel/runtime': 7.23.9 + dev: false + + /metro-source-map@0.80.8: + resolution: {integrity: sha512-+OVISBkPNxjD4eEKhblRpBf463nTMk3KMEeYS8Z4xM/z3qujGJGSsWUGRtH27+c6zElaSGtZFiDMshEb8mMKQg==} + engines: {node: '>=18'} + dependencies: + '@babel/traverse': 7.24.1 + '@babel/types': 7.24.0 + invariant: 2.2.4 + metro-symbolicate: 0.80.8 + nullthrows: 1.1.1 + ob1: 0.80.8 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /metro-symbolicate@0.80.8: + resolution: {integrity: sha512-nwhYySk79jQhwjL9QmOUo4wS+/0Au9joEryDWw7uj4kz2yvw1uBjwmlql3BprQCBzRdB3fcqOP8kO8Es+vE31g==} + engines: {node: '>=18'} + hasBin: true + dependencies: + invariant: 2.2.4 + metro-source-map: 0.80.8 + nullthrows: 1.1.1 + source-map: 0.5.7 + through2: 2.0.5 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /metro-transform-plugins@0.80.8: + resolution: {integrity: sha512-sSu8VPL9Od7w98MftCOkQ1UDeySWbsIAS5I54rW22BVpPnI3fQ42srvqMLaJUQPjLehUanq8St6OMBCBgH/UWw==} + engines: {node: '>=18'} + dependencies: + '@babel/core': 7.24.3 + '@babel/generator': 7.24.1 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.1 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + dev: false + + /metro-transform-worker@0.80.8: + resolution: {integrity: sha512-+4FG3TQk3BTbNqGkFb2uCaxYTfsbuFOCKMMURbwu0ehCP8ZJuTUramkaNZoATS49NSAkRgUltgmBa4YaKZ5mqw==} + engines: {node: '>=18'} + dependencies: + '@babel/core': 7.24.3 + '@babel/generator': 7.24.1 + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 + metro: 0.80.8 + metro-babel-transformer: 0.80.8 + metro-cache: 0.80.8 + metro-cache-key: 0.80.8 + metro-minify-terser: 0.80.8 + metro-source-map: 0.80.8 + metro-transform-plugins: 0.80.8 + nullthrows: 1.1.1 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false - /meow@6.1.1: - resolution: {integrity: sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==} - engines: {node: '>=8'} + /metro@0.80.8: + resolution: {integrity: sha512-in7S0W11mg+RNmcXw+2d9S3zBGmCARDxIwoXJAmLUQOQoYsRP3cpGzyJtc7WOw8+FXfpgXvceD0u+PZIHXEL7g==} + engines: {node: '>=18'} + hasBin: true dependencies: - '@types/minimist': 1.2.5 - camelcase-keys: 6.2.2 - decamelize-keys: 1.1.1 - hard-rejection: 2.1.0 - minimist-options: 4.1.0 - normalize-package-data: 2.5.0 - read-pkg-up: 7.0.1 - redent: 3.0.0 - trim-newlines: 3.0.1 - type-fest: 0.13.1 - yargs-parser: 18.1.3 - dev: true - - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true - - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: true + '@babel/code-frame': 7.24.2 + '@babel/core': 7.24.3 + '@babel/generator': 7.24.1 + '@babel/parser': 7.24.1 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.1 + '@babel/types': 7.24.0 + accepts: 1.3.8 + chalk: 4.1.2 + ci-info: 2.0.0 + connect: 3.7.0 + debug: 2.6.9 + denodeify: 1.2.1 + error-stack-parser: 2.1.4 + graceful-fs: 4.2.11 + hermes-parser: 0.20.1 + image-size: 1.1.1 + invariant: 2.2.4 + jest-worker: 29.7.0 + jsc-safe-url: 0.2.4 + lodash.throttle: 4.1.1 + metro-babel-transformer: 0.80.8 + metro-cache: 0.80.8 + metro-cache-key: 0.80.8 + metro-config: 0.80.8 + metro-core: 0.80.8 + metro-file-map: 0.80.8 + metro-resolver: 0.80.8 + metro-runtime: 0.80.8 + metro-source-map: 0.80.8 + metro-symbolicate: 0.80.8 + metro-transform-plugins: 0.80.8 + metro-transform-worker: 0.80.8 + mime-types: 2.1.35 + node-fetch: 2.7.0 + nullthrows: 1.1.1 + rimraf: 3.0.2 + serialize-error: 2.1.0 + source-map: 0.5.7 + strip-ansi: 6.0.1 + throat: 5.0.0 + ws: 7.5.9 + yargs: 17.7.2 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false /micromark@2.11.4: resolution: {integrity: sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==} @@ -5730,6 +8401,30 @@ packages: braces: 3.0.2 picomatch: 2.3.1 + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + + /mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + dev: false + + /mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + dev: false + /mime@3.0.0: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} engines: {node: '>=10.0.0'} @@ -5739,13 +8434,17 @@ packages: /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - dev: true /mimic-fn@4.0.0: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} dev: true + /mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + dev: false + /min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -5755,7 +8454,6 @@ packages: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 - dev: true /minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} @@ -5775,7 +8473,6 @@ packages: /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true /minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} @@ -5820,18 +8517,20 @@ packages: engines: {node: '>= 8.0.0'} dev: true + /mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + dev: false + /mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true dependencies: minimist: 1.2.8 - dev: true /mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true - dev: true /mlly@1.6.1: resolution: {integrity: sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==} @@ -5886,13 +8585,15 @@ packages: engines: {node: '>=10'} dev: true + /ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + dev: false + /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true /msgpackr-extract@3.0.2: resolution: {integrity: sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==} @@ -5918,12 +8619,41 @@ packages: resolution: {integrity: sha512-MNAym1D9GTpY0/CKYJFDmaJ3TfhblfsQyyipCCSsgasMZCAyR2fCNDJhR7lACfJ0YMwQSDi5RHeIdJcsze6WMg==} dev: false + /mysql2@3.9.4: + resolution: {integrity: sha512-OEESQuwxMza803knC1YSt7NMuc1BrK9j7gZhCSs2WAyxr1vfiI7QLaLOKTh5c9SWGz98qVyQUbK8/WckevNQhg==} + engines: {node: '>= 8.0'} + dependencies: + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.6.3 + long: 5.2.3 + lru-cache: 8.0.5 + named-placeholders: 1.1.3 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + dev: false + + /named-placeholders@1.1.3: + resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} + engines: {node: '>=12.0.0'} + dependencies: + lru-cache: 7.18.3 + dev: false + /nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true dev: true + /napi-build-utils@1.0.2: + resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} + dev: false + + /native-duplexpair@1.0.0: + resolution: {integrity: sha512-E7QQoM+3jvNtlmyfqRZ0/U75VFgCls+fSkbml2MpgWkWyz3ox8Y58gNhfuziuQYGNNQAbFZJQck55LHCnCK6CA==} + dev: false + /natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} dev: true @@ -5932,9 +8662,29 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + dev: false + /neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - dev: true + + /nocache@3.0.4: + resolution: {integrity: sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==} + engines: {node: '>=12.0.0'} + dev: false + + /node-abi@3.57.0: + resolution: {integrity: sha512-Dp+A9JWxRaKuHP35H77I4kCKesDy5HUDEmScia2FyncMTOXASMyg251F5PhFoDA5uqBrDDffiLpbqnrZmNXW+g==} + engines: {node: '>=10'} + dependencies: + semver: 7.6.0 + dev: false + + /node-abort-controller@3.1.1: + resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} + dev: false /node-addon-api@6.1.0: resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} @@ -5950,7 +8700,6 @@ packages: engines: {node: '>= 0.10.5'} dependencies: minimatch: 3.1.2 - dev: true /node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} @@ -5962,7 +8711,6 @@ packages: optional: true dependencies: whatwg-url: 5.0.0 - dev: true /node-gyp-build-optional-packages@5.0.7: resolution: {integrity: sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==} @@ -5977,9 +8725,12 @@ packages: detect-libc: 2.0.3 dev: true + /node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + dev: false + /node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} - dev: true /node-source-walk@4.3.0: resolution: {integrity: sha512-8Q1hXew6ETzqKRAs3jjLioSxNfT1cx74ooiF8RlAONwVMcfq+UdzLC2eB5qcPldUxaE5w3ytLkrmV1TGddhZTA==} @@ -5995,6 +8746,11 @@ packages: '@babel/parser': 7.23.9 dev: true + /node-stream-zip@1.15.0: + resolution: {integrity: sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==} + engines: {node: '>=0.12.0'} + dev: false + /normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: @@ -6008,8 +8764,13 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} requiresBuild: true - dev: true - optional: true + + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: false /npm-run-path@5.3.0: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} @@ -6018,6 +8779,20 @@ packages: path-key: 4.0.0 dev: true + /nullthrows@1.1.1: + resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} + dev: false + + /ob1@0.80.8: + resolution: {integrity: sha512-QHJQk/lXMmAW8I7AIM3in1MSlwe1umR72Chhi8B7Xnq6mzjhBKkA6Fy/zAhQnGkA4S912EPCEvTij5yh+EQTAA==} + engines: {node: '>=18'} + dev: false + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: false + /object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} dev: true @@ -6072,18 +8847,35 @@ packages: es-abstract: 1.22.4 dev: true + /on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 + dev: false + + /on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 + dev: false + + /on-headers@1.0.2: + resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} + engines: {node: '>= 0.8'} + dev: false + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 - dev: true /onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} dependencies: mimic-fn: 2.1.0 - dev: true /onetime@6.0.0: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} @@ -6092,6 +8884,30 @@ packages: mimic-fn: 4.0.0 dev: true + /open@6.4.0: + resolution: {integrity: sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==} + engines: {node: '>=8'} + dependencies: + is-wsl: 1.1.0 + dev: false + + /open@7.4.2: + resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} + engines: {node: '>=8'} + dependencies: + is-docker: 2.2.1 + is-wsl: 2.2.0 + dev: false + + /open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + dev: false + /optionator@0.9.3: resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} @@ -6117,7 +8933,6 @@ packages: log-symbols: 4.1.0 strip-ansi: 6.0.1 wcwidth: 1.0.1 - dev: true /ordered-binary@1.5.1: resolution: {integrity: sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==} @@ -6144,14 +8959,12 @@ packages: engines: {node: '>=6'} dependencies: p-try: 2.2.0 - dev: true /p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} dependencies: yocto-queue: 0.1.0 - dev: true /p-limit@5.0.0: resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} @@ -6165,21 +8978,18 @@ packages: engines: {node: '>=6'} dependencies: p-limit: 2.3.0 - dev: true /p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} dependencies: p-limit: 2.3.0 - dev: true /p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} dependencies: p-limit: 3.1.0 - dev: true /p-map@2.1.0: resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} @@ -6189,7 +8999,6 @@ packages: /p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - dev: true /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} @@ -6209,6 +9018,14 @@ packages: is-hexadecimal: 1.0.4 dev: true + /parse-json@4.0.0: + resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} + engines: {node: '>=4'} + dependencies: + error-ex: 1.3.2 + json-parse-better-errors: 1.0.2 + dev: false + /parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -6224,6 +9041,11 @@ packages: engines: {node: '>=6'} dev: true + /parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + dev: false + /path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} dev: false @@ -6231,22 +9053,18 @@ packages: /path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} - dev: true /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - dev: true /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} - dev: true /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - dev: true /path-key@4.0.0: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} @@ -6255,7 +9073,6 @@ packages: /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true /path-scurry@1.10.1: resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} @@ -6280,7 +9097,6 @@ packages: /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -6289,19 +9105,16 @@ packages: /pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} - dev: true /pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} - dev: true /pkg-dir@3.0.0: resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} engines: {node: '>=6'} dependencies: find-up: 3.0.0 - dev: true /pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} @@ -6374,6 +9187,30 @@ packages: source-map-js: 1.2.0 dev: true + /postgres@3.4.4: + resolution: {integrity: sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==} + engines: {node: '>=12'} + dev: false + + /prebuild-install@7.1.2: + resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} + engines: {node: '>=10'} + hasBin: true + dependencies: + detect-libc: 2.0.3 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 1.0.2 + node-abi: 3.57.0 + pump: 3.0.0 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.1 + tunnel-agent: 0.6.0 + dev: false + /precinct@11.0.5: resolution: {integrity: sha512-oHSWLC8cL/0znFhvln26D14KfCQFFn4KOLSw6hmLhd+LQ2SKt9Ljm89but76Pc7flM9Ty1TnXyrA2u16MfRV3w==} engines: {node: ^14.14.0 || >=16.0.0} @@ -6444,6 +9281,16 @@ packages: hasBin: true dev: true + /pretty-format@26.6.2: + resolution: {integrity: sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==} + engines: {node: '>= 10'} + dependencies: + '@jest/types': 26.6.2 + ansi-regex: 5.0.1 + ansi-styles: 4.3.0 + react-is: 17.0.2 + dev: false + /pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6451,7 +9298,6 @@ packages: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 react-is: 18.2.0 - dev: true /pretty-ms@7.0.1: resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} @@ -6462,12 +9308,45 @@ packages: /process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - dev: true + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: false + + /promise@8.3.0: + resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} + dependencies: + asap: 2.0.6 + dev: false + + /prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + dev: false + + /prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + dev: false /pseudomap@1.0.2: resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} dev: true + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: false + /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -6481,6 +9360,12 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true + /queue@6.0.2: + resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + dependencies: + inherits: 2.0.4 + dev: false + /quick-lru@4.0.1: resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} engines: {node: '>=8'} @@ -6499,6 +9384,11 @@ packages: math-random: 1.0.4 dev: true + /range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + dev: false + /rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -6507,11 +9397,114 @@ packages: ini: 1.3.8 minimist: 1.2.8 strip-json-comments: 2.0.1 - dev: true + + /react-devtools-core@4.28.5: + resolution: {integrity: sha512-cq/o30z9W2Wb4rzBefjv5fBalHU0rJGZCHAkf/RHSBWSSYwh8PlQTqqOJmgIIbBtpj27T6FIPXeomIjZtCNVqA==} + dependencies: + shell-quote: 1.8.1 + ws: 7.5.9 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + dev: false + + /react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + dev: false /react-is@18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} - dev: true + + /react-native-quick-sqlite@8.0.6(react-native@0.73.6)(react@18.2.0): + resolution: {integrity: sha512-XtwXnfZ1a6zRzAHoWFyVJsP3p8etx3/xww1oFKGdiOSj054PdYIeup9A53rtQ6ENyg+aqSKOgmxoN/PetulGOQ==} + peerDependencies: + react: '*' + react-native: '*' + dependencies: + react: 18.2.0 + react-native: 0.73.6(@babel/core@7.24.3)(@babel/preset-env@7.24.4)(react@18.2.0) + dev: false + + /react-native@0.73.6(@babel/core@7.24.3)(@babel/preset-env@7.24.4)(react@18.2.0): + resolution: {integrity: sha512-oqmZe8D2/VolIzSPZw+oUd6j/bEmeRHwsLn1xLA5wllEYsZ5zNuMsDus235ONOnCRwexqof/J3aztyQswSmiaA==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + react: 18.2.0 + dependencies: + '@jest/create-cache-key-function': 29.7.0 + '@react-native-community/cli': 12.3.6 + '@react-native-community/cli-platform-android': 12.3.6 + '@react-native-community/cli-platform-ios': 12.3.6 + '@react-native/assets-registry': 0.73.1 + '@react-native/codegen': 0.73.3(@babel/preset-env@7.24.4) + '@react-native/community-cli-plugin': 0.73.17(@babel/core@7.24.3)(@babel/preset-env@7.24.4) + '@react-native/gradle-plugin': 0.73.4 + '@react-native/js-polyfills': 0.73.1 + '@react-native/normalize-colors': 0.73.2 + '@react-native/virtualized-lists': 0.73.4(react-native@0.73.6) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + base64-js: 1.5.1 + chalk: 4.1.2 + deprecated-react-native-prop-types: 5.0.0 + event-target-shim: 5.0.1 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + jest-environment-node: 29.7.0 + jsc-android: 250231.0.0 + memoize-one: 5.2.1 + metro-runtime: 0.80.8 + metro-source-map: 0.80.8 + mkdirp: 0.5.6 + nullthrows: 1.1.1 + pretty-format: 26.6.2 + promise: 8.3.0 + react: 18.2.0 + react-devtools-core: 4.28.5 + react-refresh: 0.14.0 + react-shallow-renderer: 16.15.0(react@18.2.0) + regenerator-runtime: 0.13.11 + scheduler: 0.24.0-canary-efb381bbf-20230505 + stacktrace-parser: 0.1.10 + whatwg-fetch: 3.6.20 + ws: 6.2.2 + yargs: 17.7.2 + transitivePeerDependencies: + - '@babel/core' + - '@babel/preset-env' + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /react-refresh@0.14.0: + resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} + engines: {node: '>=0.10.0'} + dev: false + + /react-shallow-renderer@16.15.0(react@18.2.0): + resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==} + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 + dependencies: + object-assign: 4.1.1 + react: 18.2.0 + react-is: 18.2.0 + dev: false + + /react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + dev: false /read-pkg-up@7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} @@ -6552,7 +9545,6 @@ packages: safe-buffer: 5.1.2 string_decoder: 1.1.1 util-deprecate: 1.0.2 - dev: true /readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} @@ -6561,7 +9553,17 @@ packages: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 - dev: true + + /readable-stream@4.5.2: + resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + dev: false /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} @@ -6572,6 +9574,10 @@ packages: dev: true optional: true + /readline@1.3.0: + resolution: {integrity: sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==} + dev: false + /recast@0.20.5: resolution: {integrity: sha512-E5qICoPoNL4yU0H0NoBDntNB0Q5oMSNh9usFctYniLBluTthi3RsQVBXIJNbApOlvSwW/RGxIuokPcAc59J5fQ==} engines: {node: '>= 4'} @@ -6582,6 +9588,16 @@ packages: tslib: 2.6.2 dev: true + /recast@0.21.5: + resolution: {integrity: sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg==} + engines: {node: '>= 4'} + dependencies: + ast-types: 0.15.2 + esprima: 4.0.1 + source-map: 0.6.1 + tslib: 2.6.2 + dev: false + /recast@0.23.6: resolution: {integrity: sha512-9FHoNjX1yjuesMwuthAmPKabxYQdOgihFYmT5ebXfYGBcnqXZf3WOVz+5foEZ8Y83P4ZY6yQD5GMmtV+pgCCAQ==} engines: {node: '>= 4'} @@ -6613,9 +9629,29 @@ packages: redis-errors: 1.2.0 dev: true + /regenerate-unicode-properties@10.1.1: + resolution: {integrity: sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==} + engines: {node: '>=4'} + dependencies: + regenerate: 1.4.2 + dev: false + + /regenerate@1.4.2: + resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + dev: false + + /regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + dev: false + /regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - dev: true + + /regenerator-transform@0.15.2: + resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} + dependencies: + '@babel/runtime': 7.23.9 + dev: false /regexp.prototype.flags@1.5.2: resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} @@ -6627,6 +9663,25 @@ packages: set-function-name: 2.0.2 dev: true + /regexpu-core@5.3.2: + resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} + engines: {node: '>=4'} + dependencies: + '@babel/regjsgen': 0.8.0 + regenerate: 1.4.2 + regenerate-unicode-properties: 10.1.1 + regjsparser: 0.9.1 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.1.0 + dev: false + + /regjsparser@0.9.1: + resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} + hasBin: true + dependencies: + jsesc: 0.5.0 + dev: false + /remarkable@1.7.4: resolution: {integrity: sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg==} engines: {node: '>= 0.10.0'} @@ -6649,7 +9704,6 @@ packages: /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} - dev: true /require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} @@ -6658,7 +9712,6 @@ packages: /require-main-filename@2.0.0: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - dev: true /requirejs-config-file@4.0.0: resolution: {integrity: sha512-jnIre8cbWOyvr8a5F2KuqBnY+SDA4NXr/hzEZJG79Mxm2WiFQz2dzhC8ibtPJS7zkmBEl1mxSwp5HhC1W4qpxw==} @@ -6679,6 +9732,11 @@ packages: engines: {node: '>=14'} dev: true + /resolve-from@3.0.0: + resolution: {integrity: sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==} + engines: {node: '>=4'} + dev: false + /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -6700,7 +9758,6 @@ packages: is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: true /restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} @@ -6708,7 +9765,6 @@ packages: dependencies: onetime: 5.1.2 signal-exit: 3.0.7 - dev: true /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} @@ -6720,14 +9776,12 @@ packages: hasBin: true dependencies: glob: 7.2.3 - dev: true /rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} hasBin: true dependencies: glob: 7.2.3 - dev: true /rimraf@5.0.5: resolution: {integrity: sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==} @@ -6778,11 +9832,9 @@ packages: /safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - dev: true /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: true /safe-regex-test@1.0.3: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} @@ -6795,7 +9847,6 @@ packages: /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - dev: true /sass-lookup@5.0.1: resolution: {integrity: sha512-t0X5PaizPc2H4+rCwszAqHZRtr4bugo4pgiCvrBFvIX0XFxnr29g77LJcpyj9A0DcKf7gXMLcgvRjsonYI6x4g==} @@ -6805,15 +9856,19 @@ packages: commander: 10.0.1 dev: true + /scheduler@0.24.0-canary-efb381bbf-20230505: + resolution: {integrity: sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA==} + dependencies: + loose-envify: 1.4.0 + dev: false + /semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true - dev: true /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - dev: true /semver@7.6.0: resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} @@ -6821,11 +9876,51 @@ packages: hasBin: true dependencies: lru-cache: 6.0.0 - dev: true + + /send@0.18.0: + resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} + engines: {node: '>= 0.8.0'} + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + dev: false + + /serialize-error@2.1.0: + resolution: {integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==} + engines: {node: '>=0.10.0'} + dev: false + + /serve-static@1.15.0: + resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} + engines: {node: '>= 0.8.0'} + dependencies: + encodeurl: 1.0.2 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.18.0 + transitivePeerDependencies: + - supports-color + dev: false /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - dev: true /set-function-length@1.2.1: resolution: {integrity: sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==} @@ -6856,12 +9951,15 @@ packages: to-object-path: 0.3.0 dev: true + /setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + dev: false + /shallow-clone@3.0.1: resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} engines: {node: '>=8'} dependencies: kind-of: 6.0.3 - dev: true /shebang-command@1.2.0: resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} @@ -6875,7 +9973,6 @@ packages: engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 - dev: true /shebang-regex@1.0.0: resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} @@ -6885,7 +9982,10 @@ packages: /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - dev: true + + /shell-quote@1.8.1: + resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} + dev: false /side-channel@1.0.5: resolution: {integrity: sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==} @@ -6903,13 +10003,24 @@ packages: /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: true /signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} dev: true + /simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + dev: false + + /simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + dev: false + /sirv@2.0.4: resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} engines: {node: '>= 10'} @@ -6919,6 +10030,10 @@ packages: totalist: 3.0.1 dev: true + /sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + dev: false + /slash@2.0.0: resolution: {integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==} engines: {node: '>=6'} @@ -6927,7 +10042,15 @@ packages: /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - dev: true + + /slice-ansi@2.1.0: + resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==} + engines: {node: '>=6'} + dependencies: + ansi-styles: 3.2.1 + astral-regex: 1.0.0 + is-fullwidth-code-point: 2.0.0 + dev: false /smartwrap@2.0.2: resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==} @@ -6957,17 +10080,19 @@ packages: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - dev: true /source-map@0.5.7: resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} engines: {node: '>=0.10.0'} - dev: true /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - dev: true + + /source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + dev: false /spawndamnit@2.0.0: resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==} @@ -7000,27 +10125,60 @@ packages: /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: true + + /sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + dev: false + + /sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + dev: false /stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} dependencies: escape-string-regexp: 2.0.0 - dev: true /stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} dev: true + /stackframe@1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + dev: false + + /stacktrace-parser@0.1.10: + resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} + engines: {node: '>=6'} + dependencies: + type-fest: 0.7.1 + dev: false + /standard-as-callback@2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} dev: true + /statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + dev: false + + /statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + dev: false + /std-env@3.7.0: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} dev: true + /stoppable@1.1.0: + resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} + engines: {node: '>=4', npm: '>=6'} + dev: false + /stream-to-array@2.3.0: resolution: {integrity: sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==} dependencies: @@ -7040,7 +10198,6 @@ packages: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true /string-width@5.1.2: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} @@ -7080,13 +10237,11 @@ packages: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: safe-buffer: 5.1.2 - dev: true /string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} dependencies: safe-buffer: 5.2.1 - dev: true /stringify-object@3.3.0: resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==} @@ -7097,12 +10252,18 @@ packages: is-regexp: 1.0.0 dev: true + /strip-ansi@5.2.0: + resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} + engines: {node: '>=6'} + dependencies: + ansi-regex: 4.1.1 + dev: false + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 - dev: true /strip-ansi@7.1.0: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} @@ -7126,6 +10287,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: false + /strip-final-newline@3.0.0: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} @@ -7141,7 +10307,6 @@ packages: /strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} - dev: true /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} @@ -7154,6 +10319,10 @@ packages: js-tokens: 8.0.3 dev: true + /strnum@1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + dev: false + /stylus-lookup@5.0.1: resolution: {integrity: sha512-tLtJEd5AGvnVy4f9UHQMw4bkJJtaAcmo54N+ovQBjDY3DuWyK9Eltxzr5+KG0q4ew6v2EHyuWWNnHeiw/Eo7rQ==} engines: {node: '>=14'} @@ -7162,30 +10331,58 @@ packages: commander: 10.0.1 dev: true + /sudo-prompt@9.2.1: + resolution: {integrity: sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==} + dev: false + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} dependencies: has-flag: 3.0.0 - dev: true /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} dependencies: has-flag: 4.0.0 - dev: true + + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + dev: false /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - dev: true /tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} dev: true + /tar-fs@2.1.1: + resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.0 + tar-stream: 2.2.0 + dev: false + + /tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: false + /tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} @@ -7198,18 +10395,50 @@ packages: yallist: 4.0.0 dev: true + /tedious@18.1.0: + resolution: {integrity: sha512-3o9VZDPY9B5JBEsD0BuLXxvyRDFP11YVQS3JXr1JmV+0aISbpsn/Hj9LycyxAGBzdD1gU4Z2ME5RGq43QHdRNw==} + engines: {node: '>=18'} + dependencies: + '@azure/identity': 3.4.2 + '@azure/keyvault-keys': 4.8.0 + '@js-joda/core': 5.6.2 + '@types/node': 20.11.30 + bl: 6.0.12 + iconv-lite: 0.6.3 + js-md4: 0.3.2 + native-duplexpair: 1.0.0 + sprintf-js: 1.1.3 + transitivePeerDependencies: + - supports-color + dev: false + + /temp-dir@2.0.0: + resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} + engines: {node: '>=8'} + dev: false + /temp@0.8.4: resolution: {integrity: sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==} engines: {node: '>=6.0.0'} dependencies: rimraf: 2.6.3 - dev: true /term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} dev: true + /terser@5.30.3: + resolution: {integrity: sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.6 + acorn: 8.11.3 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: false + /test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} @@ -7223,12 +10452,15 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true + /throat@5.0.0: + resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} + dev: false + /through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} dependencies: readable-stream: 2.3.8 xtend: 4.0.2 - dev: true /tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -7255,10 +10487,13 @@ packages: os-tmpdir: 1.0.2 dev: true + /tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + dev: false + /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} - dev: true /to-object-path@0.3.0: resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} @@ -7274,6 +10509,11 @@ packages: dependencies: is-number: 7.0.0 + /toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + dev: false + /toml@3.0.0: resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} dev: false @@ -7285,7 +10525,6 @@ packages: /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - dev: true /trim-newlines@3.0.1: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} @@ -7339,7 +10578,6 @@ packages: /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - dev: true /tslint@6.1.3(typescript@5.4.3): resolution: {integrity: sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==} @@ -7409,6 +10647,12 @@ packages: yargs: 17.7.2 dev: true + /tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + dependencies: + safe-buffer: 5.2.1 + dev: false + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -7419,7 +10663,6 @@ packages: /type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} - dev: true /type-fest@0.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} @@ -7436,6 +10679,11 @@ packages: engines: {node: '>=8'} dev: true + /type-fest@0.7.1: + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} + engines: {node: '>=8'} + dev: false + /type-fest@0.8.1: resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} engines: {node: '>=8'} @@ -7510,13 +10758,35 @@ packages: /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true /undici@6.10.1: resolution: {integrity: sha512-kSzmWrOx3XBKTgPm4Tal8Hyl3yf+hzlA00SAf4goxv8LZYafKmS6gJD/7Fe5HH/DMNiFTRXvkwhLo7mUn5fuQQ==} engines: {node: '>=18.0'} dev: false + /unicode-canonical-property-names-ecmascript@2.0.0: + resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} + engines: {node: '>=4'} + dev: false + + /unicode-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.0 + unicode-property-aliases-ecmascript: 2.1.0 + dev: false + + /unicode-match-property-value-ecmascript@2.1.0: + resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} + engines: {node: '>=4'} + dev: false + + /unicode-property-aliases-ecmascript@2.1.0: + resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} + engines: {node: '>=4'} + dev: false + /unist-util-stringify-position@2.0.3: resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} dependencies: @@ -7526,13 +10796,17 @@ packages: /universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} - dev: true /universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} dev: true + /unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + dev: false + /update-browserslist-db@1.0.13(browserslist@4.23.0): resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} hasBin: true @@ -7542,7 +10816,6 @@ packages: browserslist: 4.23.0 escalade: 3.1.2 picocolors: 1.0.0 - dev: true /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -7552,7 +10825,16 @@ packages: /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - dev: true + + /utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + dev: false + + /uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + dev: false /v8-to-istanbul@9.2.0: resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} @@ -7570,6 +10852,11 @@ packages: spdx-expression-parse: 3.0.1 dev: true + /vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + dev: false + /vite-node@1.4.0(@types/node@20.11.30): resolution: {integrity: sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==} engines: {node: ^18.0.0 || >=20.0.0} @@ -7695,16 +10982,25 @@ packages: - terser dev: true + /vlq@1.0.1: + resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} + dev: false + /walkdir@0.4.1: resolution: {integrity: sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==} engines: {node: '>=6.0.0'} dev: true + /walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + dependencies: + makeerror: 1.0.12 + dev: false + /wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: defaults: 1.0.4 - dev: true /weak-lru-cache@1.2.2: resolution: {integrity: sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==} @@ -7712,13 +11008,16 @@ packages: /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - dev: true /webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} dev: true + /whatwg-fetch@3.6.20: + resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} + dev: false + /whatwg-mimetype@3.0.0: resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} engines: {node: '>=12'} @@ -7729,7 +11028,6 @@ packages: dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 - dev: true /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} @@ -7743,7 +11041,6 @@ packages: /which-module@2.0.1: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - dev: true /which-pm@2.0.0: resolution: {integrity: sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==} @@ -7777,7 +11074,6 @@ packages: hasBin: true dependencies: isexe: 2.0.0 - dev: true /why-is-node-running@2.2.2: resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} @@ -7795,7 +11091,6 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true /wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} @@ -7804,7 +11099,6 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true /wrap-ansi@8.1.0: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} @@ -7817,7 +11111,6 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true /write-file-atomic@2.4.3: resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==} @@ -7825,7 +11118,33 @@ packages: graceful-fs: 4.2.11 imurmurhash: 0.1.4 signal-exit: 3.0.7 - dev: true + + /ws@6.2.2: + resolution: {integrity: sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dependencies: + async-limiter: 1.0.1 + dev: false + + /ws@7.5.9: + resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false /ws@8.16.0: resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} @@ -7842,16 +11161,13 @@ packages: /xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} - dev: true /y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - dev: true /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - dev: true /yallist@2.1.2: resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} @@ -7859,11 +11175,9 @@ packages: /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true /yaml@2.4.1: resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==} @@ -7877,12 +11191,10 @@ packages: dependencies: camelcase: 5.3.1 decamelize: 1.2.0 - dev: true /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - dev: true /yargs@15.4.1: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} @@ -7899,7 +11211,6 @@ packages: which-module: 2.0.1 y18n: 4.0.3 yargs-parser: 18.1.3 - dev: true /yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} @@ -7912,12 +11223,10 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 - dev: true /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - dev: true /yocto-queue@1.0.0: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} @@ -7928,10 +11237,10 @@ packages: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} dev: true - github.com/effect-ts/markdown-toc/4bfeb0f140105440ea0d12df2fa23199cc3ec1d5: - resolution: {tarball: https://codeload.github.com/effect-ts/markdown-toc/tar.gz/4bfeb0f140105440ea0d12df2fa23199cc3ec1d5} - name: markdown-toc - version: 1.2.0 + github.com/effect-ts/markdown-toc/3ea4550bf1352c612aa8b9e582dc263a89f2b64d: + resolution: {tarball: https://codeload.github.com/effect-ts/markdown-toc/tar.gz/3ea4550bf1352c612aa8b9e582dc263a89f2b64d} + name: '@effect/markdown-toc' + version: 0.1.0 engines: {node: '>=0.10.0'} hasBin: true dependencies: diff --git a/scripts/circular.mjs b/scripts/circular.mjs new file mode 100644 index 0000000000..809e3f1ce4 --- /dev/null +++ b/scripts/circular.mjs @@ -0,0 +1,23 @@ +/* eslint-disable no-undef */ +import * as glob from "glob" +import madge from "madge" + +madge( + glob.globSync("packages/*/src/**/*.ts", { + ignore: ["packages/sql-sqlite-bun/**"] + }), + { + detectiveOptions: { + ts: { + skipTypeImports: true + } + } + } +).then((res) => { + const circular = res.circular() + if (circular.length) { + console.error("Circular dependencies found") + console.error(circular) + process.exit(1) + } +}) diff --git a/tsconfig.base.json b/tsconfig.base.json index 9d2a1d94cd..f8243198f9 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -87,6 +87,40 @@ "@effect/schema": ["./packages/schema/src/index.js"], "@effect/schema/*": ["./packages/schema/src/*.js"], "@effect/schema/test/*": ["./packages/schema/test/*.js"], + "@effect/sql": ["./packages/sql/src/index.js"], + "@effect/sql/*": ["./packages/sql/src/*.js"], + "@effect/sql/test/*": ["./packages/sql/test/*.js"], + "@effect/sql-mssql": ["./packages/sql-mssql/src/index.js"], + "@effect/sql-mssql/*": ["./packages/sql-mssql/src/*.js"], + "@effect/sql-mssql/test/*": ["./packages/sql-mssql/test/*.js"], + "@effect/sql-mysql2": ["./packages/sql-mysql2/src/index.js"], + "@effect/sql-mysql2/*": ["./packages/sql-mysql2/src/*.js"], + "@effect/sql-mysql2/test/*": ["./packages/sql-mysql2/test/*.js"], + "@effect/sql-pg": ["./packages/sql-pg/src/index.js"], + "@effect/sql-pg/*": ["./packages/sql-pg/src/*.js"], + "@effect/sql-pg/test/*": ["./packages/sql-pg/test/*.js"], + "@effect/sql-sqlite-bun": ["./packages/sql-sqlite-bun/src/index.js"], + "@effect/sql-sqlite-bun/*": ["./packages/sql-sqlite-bun/src/*.js"], + "@effect/sql-sqlite-bun/test/*": ["./packages/sql-sqlite-bun/test/*.js"], + "@effect/sql-sqlite-node": ["./packages/sql-sqlite-node/src/index.js"], + "@effect/sql-sqlite-node/*": ["./packages/sql-sqlite-node/src/*.js"], + "@effect/sql-sqlite-node/test/*": [ + "./packages/sql-sqlite-node/test/*.js" + ], + "@effect/sql-sqlite-react-native": [ + "./packages/sql-sqlite-react-native/src/index.js" + ], + "@effect/sql-sqlite-react-native/*": [ + "./packages/sql-sqlite-react-native/src/*.js" + ], + "@effect/sql-sqlite-react-native/test/*": [ + "./packages/sql-sqlite-react-native/test/*.js" + ], + "@effect/sql-sqlite-wasm": ["./packages/sql-sqlite-wasm/src/index.js"], + "@effect/sql-sqlite-wasm/*": ["./packages/sql-sqlite-wasm/src/*.js"], + "@effect/sql-sqlite-wasm/test/*": [ + "./packages/sql-sqlite-wasm/test/*.js" + ], "@effect/typeclass": ["./packages/typeclass/src/index.js"], "@effect/typeclass/*": ["./packages/typeclass/src/*.js"], "@effect/typeclass/test/*": ["./packages/typeclass/test/*.js"], diff --git a/tsconfig.build.json b/tsconfig.build.json index f4b07cfb22..068217301d 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -16,6 +16,14 @@ { "path": "packages/rpc/tsconfig.build.json" }, { "path": "packages/rpc-http/tsconfig.build.json" }, { "path": "packages/schema/tsconfig.build.json" }, + { "path": "packages/sql/tsconfig.build.json" }, + { "path": "packages/sql-mysql2/tsconfig.build.json" }, + { "path": "packages/sql-mssql/tsconfig.build.json" }, + { "path": "packages/sql-pg/tsconfig.build.json" }, + { "path": "packages/sql-sqlite-bun/tsconfig.build.json" }, + { "path": "packages/sql-sqlite-node/tsconfig.build.json" }, + { "path": "packages/sql-sqlite-react-native/tsconfig.build.json" }, + { "path": "packages/sql-sqlite-wasm/tsconfig.build.json" }, { "path": "packages/typeclass/tsconfig.build.json" }, { "path": "packages/vitest/tsconfig.build.json" } ] diff --git a/tsconfig.json b/tsconfig.json index 74aecf9694..6780488534 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,6 +17,14 @@ { "path": "packages/rpc-http" }, { "path": "packages/schema" }, { "path": "packages/schema" }, + { "path": "packages/sql" }, + { "path": "packages/sql-mssql" }, + { "path": "packages/sql-mysql2" }, + { "path": "packages/sql-pg" }, + { "path": "packages/sql-sqlite-bun" }, + { "path": "packages/sql-sqlite-node" }, + { "path": "packages/sql-sqlite-react-native" }, + { "path": "packages/sql-sqlite-wasm" }, { "path": "packages/typeclass" }, { "path": "packages/vitest" } ] diff --git a/vitest.shared.ts b/vitest.shared.ts index 09354b0e22..bcd62a66db 100644 --- a/vitest.shared.ts +++ b/vitest.shared.ts @@ -11,6 +11,9 @@ const config: UserConfig = { esbuild: { target: "es2020" }, + optimizeDeps: { + exclude: ["bun:sqlite"] + }, test: { fakeTimers: { toFake: undefined @@ -18,6 +21,7 @@ const config: UserConfig = { sequence: { concurrent: true }, + include: ["test/**/*.test.ts"], alias: { // TODO: Should we use `effect/test` instead of `effect-test`? "effect-test": path.join(__dirname, "packages/effect/test"), @@ -35,6 +39,14 @@ const config: UserConfig = { ...alias("rpc"), ...alias("rpc-http"), ...alias("schema"), + ...alias("sql"), + ...alias("sql-mssql"), + ...alias("sql-mysql2"), + ...alias("sql-pg"), + ...alias("sql-sqlite-bun"), + ...alias("sql-sqlite-node"), + ...alias("sql-sqlite-react-native"), + ...alias("sql-sqlite-wasm"), ...alias("typeclass"), ...alias("vitest") }