diff --git a/changelogs/drizzle-orm/0.17.3.md b/changelogs/drizzle-orm/0.17.3.md new file mode 100644 index 000000000..a97d45962 --- /dev/null +++ b/changelogs/drizzle-orm/0.17.3.md @@ -0,0 +1,22 @@ +We have released [AWS Data API support](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html) for PostgreSQL + +--- + +Connection example + +```typescript +import { drizzle, migrate } from 'drizzle-orm/aws-data-api/pg'; + +const rdsClient = new RDSDataClient({}); + +const db = drizzle(rdsClient, { + database: '', + secretArn: '', + resourceArn: '', +}); + +await migrate(db, { migrationsFolder: '' }); +``` + +> **Note**: +> All drizzle pg data types are working well with data api, except of `interval`. This type is not yet mapped in proper way \ No newline at end of file diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index e61fbd4ff..a0ae76ff8 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.17.2", + "version": "0.17.3", "description": "Drizzle ORM package for SQL databases", "scripts": { "build": "tsc && resolve-tspaths && cp ../README.md package.json dist/", @@ -39,12 +39,13 @@ "@types/pg": "*", "@types/sql.js": "*", "better-sqlite3": ">=7 <9", + "bun-types": "*", "mysql2": ">=2 <3", "pg": ">=8 <9", "postgres": ">=3 <4", "sql.js": ">=1 <2", "sqlite3": ">=5 <6", - "bun-types": "*" + "@aws-sdk/client-rds-data": ">=3 <4" }, "peerDependenciesMeta": { "mysql2": { @@ -82,9 +83,13 @@ }, "bun-types": { "optional": true + }, + "@aws-sdk/client-rds-data": { + "optional": true } }, "devDependencies": { + "@aws-sdk/client-rds-data": "^3.257.0", "@cloudflare/workers-types": "^3.18.0", "@neondatabase/serverless": "^0.1.13", "@types/better-sqlite3": "^7.6.2", diff --git a/drizzle-orm/src/aws-data-api/common/index.ts b/drizzle-orm/src/aws-data-api/common/index.ts new file mode 100644 index 000000000..dbb899f04 --- /dev/null +++ b/drizzle-orm/src/aws-data-api/common/index.ts @@ -0,0 +1,72 @@ +import { Field, TypeHint } from "@aws-sdk/client-rds-data"; +import { QueryTypingsValue } from "~/sql"; + +export function getValueFromDataApi(row: Field) { + if (typeof row.stringValue !== 'undefined') { + return row.stringValue; + } else if (typeof row.booleanValue !== 'undefined') { + return row.booleanValue; + } else if (typeof row.doubleValue !== 'undefined') { + return row.doubleValue; + } else if (typeof row.isNull !== 'undefined') { + return null; + } else if (typeof row.longValue !== 'undefined') { + return row.longValue; + } else if (typeof row.blobValue !== 'undefined') { + return row.blobValue; + } else if (typeof row.arrayValue !== 'undefined') { + if (typeof row.arrayValue.stringValues !== 'undefined') { + return row.arrayValue.stringValues; + } + throw Error('Unknown array type'); + } else { + throw Error('Unknown type'); + } +} + +export function typingsToAwsTypeHint(typings?: QueryTypingsValue): TypeHint | undefined { + if (typings === 'date') { + return TypeHint.DATE; + } else if (typings === 'decimal') { + return TypeHint.DECIMAL; + } else if (typings === 'json') { + return TypeHint.JSON; + } else if (typings === 'time') { + return TypeHint.TIME; + } else if (typings === 'timestamp') { + return TypeHint.TIMESTAMP; + } else if (typings === 'uuid') { + return TypeHint.UUID; + } else { + return undefined; + } +} + +export function toValueParam(value: any, typings?: QueryTypingsValue): { value: Field; typeHint?: TypeHint } { + let response: { value: Field; typeHint?: TypeHint } = { + value: {} as any, + typeHint: typingsToAwsTypeHint(typings), + }; + + if (value === null) { + response.value = { isNull: true }; + } else if (typeof value === 'string') { + if (response.typeHint === 'DATE') { + response.value = { stringValue: value.split('T')[0]! }; + } else { + response.value = { stringValue: value }; + } + } else if (typeof value === 'number' && Number.isInteger(value)) { + response.value = { longValue: value }; + } else if (typeof value === 'number' && !Number.isInteger(value)) { + response.value = { doubleValue: value }; + } else if (typeof value === 'boolean') { + response.value = { booleanValue: value }; + } else if (value instanceof Date) { + response.value = { stringValue: value.toISOString().replace('T', ' ').replace('Z', '') }; + } else { + throw Error(`Unknown type for ${value}`); + } + + return response; +} \ No newline at end of file diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts new file mode 100644 index 000000000..9a743b9f7 --- /dev/null +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -0,0 +1,50 @@ +import { Logger } from '~/logger'; +import { PgDatabase } from '~/pg-core/db'; +import { PgDialect } from '~/pg-core/dialect'; +import { AwsDataApiClient, AwsDataApiPgQueryResultHKT, AwsDataApiSession } from './session'; + +export interface PgDriverOptions { + logger?: Logger; + database: string; + resourceArn: string; + secretArn: string; +} + +export class AwsDataApiDriver { + constructor( + private client: AwsDataApiClient, + private dialect: PgDialect, + private options: PgDriverOptions, + ) { + } + + createSession(): AwsDataApiSession { + return new AwsDataApiSession(this.client, this.dialect, this.options); + } +} + +export interface DrizzleConfig { + logger?: Logger; + database: string; + resourceArn: string; + secretArn: string; +} + +export type AwsDataApiPgDatabase = PgDatabase; + +export class AwsPgDialect extends PgDialect { + override escapeName(name: string): string { + return `"${name}"`; + } + + override escapeParam(num: number): string { + return `:${num + 1}`; + } +} + +export function drizzle(client: AwsDataApiClient, config: DrizzleConfig): AwsDataApiPgDatabase { + const dialect = new AwsPgDialect(); + const driver = new AwsDataApiDriver(client, dialect, config); + const session = driver.createSession(); + return new PgDatabase(dialect, session); +} diff --git a/drizzle-orm/src/aws-data-api/pg/index.ts b/drizzle-orm/src/aws-data-api/pg/index.ts new file mode 100644 index 000000000..dab649b2b --- /dev/null +++ b/drizzle-orm/src/aws-data-api/pg/index.ts @@ -0,0 +1,2 @@ +export * from './driver'; +export * from './session'; \ No newline at end of file diff --git a/drizzle-orm/src/aws-data-api/pg/migrator.ts b/drizzle-orm/src/aws-data-api/pg/migrator.ts new file mode 100644 index 000000000..30f98853b --- /dev/null +++ b/drizzle-orm/src/aws-data-api/pg/migrator.ts @@ -0,0 +1,46 @@ +import { MigrationConfig, readMigrationFiles } from '~/migrator'; +import { sql } from '~/sql'; +import { AwsDataApiPgDatabase } from './driver'; +import { AwsDataApiSession } from './session'; + +export async function migrate(db: AwsDataApiPgDatabase, config: string | MigrationConfig) { + const migrations = readMigrationFiles(config); + + // Write own aws datapi migrator + const session = db.session as AwsDataApiSession; + + const migrationTableCreate = sql`CREATE TABLE IF NOT EXISTS "drizzle"."__drizzle_migrations" ( + id SERIAL PRIMARY KEY, + hash text NOT NULL, + created_at bigint + )`; + await session.execute(sql`CREATE SCHEMA IF NOT EXISTS "drizzle"`); + await session.execute(migrationTableCreate); + + const dbMigrations = await session.execute<{ id: number; hash: string; created_at: string }[]>( + sql`SELECT id, hash, created_at FROM "drizzle"."__drizzle_migrations" ORDER BY created_at DESC LIMIT 1`, + ); + + const lastDbMigration = dbMigrations[0]; + const transactionId = await session.beginTransaction(); + + try { + for await (const migration of migrations) { + if ( + !lastDbMigration + || parseInt(lastDbMigration.created_at, 10) < migration.folderMillis + ) { + await session.executeWithTransaction(sql.raw(migration.sql), transactionId); + await session.executeWithTransaction( + sql`INSERT INTO "drizzle"."__drizzle_migrations" ("hash", "created_at") VALUES(${migration.hash}, ${migration.folderMillis})`, + transactionId, + ); + } + } + + await session.commitTransaction(transactionId!); + } catch (e) { + await session.rollbackTransaction(transactionId!); + throw e; + } +} diff --git a/drizzle-orm/src/aws-data-api/pg/session.ts b/drizzle-orm/src/aws-data-api/pg/session.ts new file mode 100644 index 000000000..5a091db51 --- /dev/null +++ b/drizzle-orm/src/aws-data-api/pg/session.ts @@ -0,0 +1,168 @@ +import { + BeginTransactionCommand, + BeginTransactionCommandInput, + CommitTransactionCommand, + CommitTransactionCommandInput, + ExecuteStatementCommand, + ExecuteStatementCommandOutput, + RDSDataClient, + RollbackTransactionCommand, + RollbackTransactionCommandInput, +} from '@aws-sdk/client-rds-data'; +import { Logger } from '~/logger'; +import { SelectFieldsOrdered } from '~/operations'; +import { PgDialect, PgSession, PreparedQuery, PreparedQueryConfig, QueryResultHKT } from '~/pg-core'; +import { fillPlaceholders, Query, QueryTypingsValue, SQL } from '~/sql'; +import { mapResultRow } from '~/utils'; +import { getValueFromDataApi, toValueParam } from '../common'; + +export type AwsDataApiClient = RDSDataClient; + +export class AwsDataApiPreparedQuery extends PreparedQuery { + private rawQuery: ExecuteStatementCommand; + + constructor( + private client: AwsDataApiClient, + queryString: string, + private params: unknown[], + private typings: QueryTypingsValue[], + private options: AwsDataApiSessionOptions, + private fields: SelectFieldsOrdered | undefined, + name: string | undefined, + transactionId: string | undefined, + ) { + super(); + this.rawQuery = new ExecuteStatementCommand({ + sql: queryString, + parameters: [], + secretArn: options.secretArn, + resourceArn: options.resourceArn, + database: options.database, + transactionId, + }); + } + + async execute(placeholderValues: Record | undefined = {}): Promise { + const params = fillPlaceholders(this.params, placeholderValues); + + this.rawQuery.input.parameters = params.map((param, index) => ({ + name: `${index + 1}`, + ...toValueParam(param, this.typings[index]), + })); + + this.options.logger?.logQuery(this.rawQuery.input.sql!, this.rawQuery.input.parameters); + + const { fields } = this; + if (!fields) { + return await this.client.send(this.rawQuery); + } + + const result = await this.client.send(this.rawQuery); + + return result.records?.map((result) => { + const mappedResult = result.map((res) => getValueFromDataApi(res)); + return mapResultRow(fields, mappedResult); + }); + } + + all(placeholderValues?: Record | undefined): Promise { + throw new Error('Method not implemented.'); + } + + values(placeholderValues?: Record | undefined): Promise { + throw new Error('Method not implemented.'); + } +} + +export interface AwsDataApiSessionOptions { + logger?: Logger; + database: string; + resourceArn: string; + secretArn: string; +} + +export class AwsDataApiSession extends PgSession { + private rawQuery: BeginTransactionCommandInput | CommitTransactionCommandInput | RollbackTransactionCommandInput; + + constructor( + private client: AwsDataApiClient, + dialect: PgDialect, + private options: AwsDataApiSessionOptions, + ) { + super(dialect); + this.rawQuery = { + secretArn: options.secretArn, + resourceArn: options.resourceArn, + database: options.database, + }; + } + + prepareQuery( + query: Query, + fields: SelectFieldsOrdered | undefined, + name: string | undefined, + ): PreparedQuery { + return new AwsDataApiPreparedQuery( + this.client, + query.sql, + query.params, + query.typings ?? [], + this.options, + fields, + name, + undefined, + ); + } + + prepareQueryWithTransaction( + query: Query, + fields: SelectFieldsOrdered | undefined, + name: string | undefined, + transactionId: string | undefined, + ): PreparedQuery { + return new AwsDataApiPreparedQuery( + this.client, + query.sql, + query.params, + query.typings ?? [], + this.options, + fields, + name, + transactionId, + ); + } + + executeWithTransaction(query: SQL, transactionId: string | undefined): Promise { + return this.prepareQueryWithTransaction( + this.dialect.sqlToQuery(query), + undefined, + undefined, + transactionId, + ).execute(); + } + + override execute(query: SQL): Promise { + return this.prepareQuery( + this.dialect.sqlToQuery(query), + undefined, + undefined, + ).execute(); + } + + async beginTransaction(): Promise { + const transactionRes = await this.client.send(new BeginTransactionCommand(this.rawQuery)); + return transactionRes.transactionId; + } + + async commitTransaction(transactionId: string): Promise { + await this.client.send(new CommitTransactionCommand({ ...this.rawQuery, transactionId })); + } + + async rollbackTransaction(transactionId: string): Promise { + await this.client.send(new RollbackTransactionCommand({ ...this.rawQuery, transactionId })); + } +} + +export interface AwsDataApiPgQueryResultHKT extends QueryResultHKT { + type: ExecuteStatementCommandOutput; +} diff --git a/drizzle-orm/src/mysql-core/query-builders/delete.ts b/drizzle-orm/src/mysql-core/query-builders/delete.ts index e83837ac8..23f7548ab 100644 --- a/drizzle-orm/src/mysql-core/query-builders/delete.ts +++ b/drizzle-orm/src/mysql-core/query-builders/delete.ts @@ -54,8 +54,9 @@ export class MySqlDelete< return this.dialect.buildDeleteQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -63,7 +64,7 @@ export class MySqlDelete< execute: MySqlRawQueryResult; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/mysql-core/query-builders/insert.ts b/drizzle-orm/src/mysql-core/query-builders/insert.ts index 21a326e8f..7a2a7a76b 100644 --- a/drizzle-orm/src/mysql-core/query-builders/insert.ts +++ b/drizzle-orm/src/mysql-core/query-builders/insert.ts @@ -98,8 +98,9 @@ export class MySqlInsert e return this.dialect.buildInsertQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -107,7 +108,7 @@ export class MySqlInsert e execute: MySqlRawQueryResult; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/mysql-core/query-builders/select.ts b/drizzle-orm/src/mysql-core/query-builders/select.ts index f5a7b8b60..c50cc010a 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.ts @@ -149,8 +149,9 @@ export class MySqlSelect< return this.dialect.buildSelectQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -158,7 +159,7 @@ export class MySqlSelect< execute: SelectResult[]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.fields, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.fields, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/mysql-core/query-builders/update.ts b/drizzle-orm/src/mysql-core/query-builders/update.ts index 64f5aa472..fca54d234 100644 --- a/drizzle-orm/src/mysql-core/query-builders/update.ts +++ b/drizzle-orm/src/mysql-core/query-builders/update.ts @@ -83,8 +83,9 @@ export class MySqlUpdate< return this.dialect.buildUpdateQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -92,7 +93,7 @@ export class MySqlUpdate< execute: MySqlRawQueryResult; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/pg-core/README.md b/drizzle-orm/src/pg-core/README.md index 777c544c5..60911d182 100644 --- a/drizzle-orm/src/pg-core/README.md +++ b/drizzle-orm/src/pg-core/README.md @@ -15,6 +15,7 @@ Drizzle ORM is a TypeScript ORM for SQL databases designed with maximum type saf | [node-postgres](https://github.com/brianc/node-postgres) | ✅ | | driver version | | [postgres.js](https://github.com/porsager/postgres) | ✅ | [Docs](/drizzle-orm/src/postgres.js/README.md) | driver version | | [NeonDB Serverless](https://github.com/neondatabase/serverless) | ✅ | | driver version | +| [AWS Data API](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-rds-data/README.md) | ✅ | | driver version ## Installation @@ -131,6 +132,20 @@ const db = drizzle(client); const allUsers = await db.select(users); ``` +### Connect using aws data api client + +```typescript +import { drizzle, migrate } from 'drizzle-orm/aws-data-api/pg'; + +const rdsClient = new RDSDataClient({}); + +const db = drizzle(rdsClient, { + database: '', + secretArn: '', + resourceArn: '', +}); +``` + ## Schema declaration This is how you declare SQL schema in `schema.ts`. You can declare tables, indexes and constraints, foreign keys and enums. Please pay attention to `export` keyword, they are mandatory if you'll be using [drizzle-kit SQL migrations generator](#migrations). diff --git a/drizzle-orm/src/pg-core/query-builders/delete.ts b/drizzle-orm/src/pg-core/query-builders/delete.ts index 93985aa7e..08aba00a0 100644 --- a/drizzle-orm/src/pg-core/query-builders/delete.ts +++ b/drizzle-orm/src/pg-core/query-builders/delete.ts @@ -58,8 +58,9 @@ export class PgDelete< return this.dialect.buildDeleteQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -67,7 +68,7 @@ export class PgDelete< execute: TReturning extends undefined ? QueryResultKind : TReturning[]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index b3cf594da..191f26e47 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -128,8 +128,9 @@ export class PgInsert< return this.dialect.buildInsertQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -137,7 +138,7 @@ export class PgInsert< execute: TReturning extends undefined ? QueryResultKind : TReturning[]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/pg-core/query-builders/select.ts b/drizzle-orm/src/pg-core/query-builders/select.ts index 9cbae76fa..4043c0c6e 100644 --- a/drizzle-orm/src/pg-core/query-builders/select.ts +++ b/drizzle-orm/src/pg-core/query-builders/select.ts @@ -151,8 +151,9 @@ export class PgSelect< return this.dialect.buildSelectQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -160,7 +161,7 @@ export class PgSelect< execute: SelectResult[]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.fields, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.fields, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/pg-core/query-builders/update.ts b/drizzle-orm/src/pg-core/query-builders/update.ts index 704eca677..23b147279 100644 --- a/drizzle-orm/src/pg-core/query-builders/update.ts +++ b/drizzle-orm/src/pg-core/query-builders/update.ts @@ -92,8 +92,9 @@ export class PgUpdate< return this.dialect.buildUpdateQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -101,7 +102,7 @@ export class PgUpdate< execute: TReturning extends undefined ? QueryResultKind : TReturning[]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/sql/index.ts b/drizzle-orm/src/sql/index.ts index 89f43c23f..28e676ead 100644 --- a/drizzle-orm/src/sql/index.ts +++ b/drizzle-orm/src/sql/index.ts @@ -1,3 +1,5 @@ +import { MySqlDate, MySqlDecimal, MySqlJson, MySqlTime, MySqlTimestamp } from '~/mysql-core'; +import { PgDate, PgJson, PgJsonb, PgNumeric, PgTime, PgTimestamp, PgUUID } from '~/pg-core'; import { AnyColumn, Column } from '../column'; import { Table } from '../table'; @@ -21,9 +23,12 @@ export interface BuildQueryConfig { escapeParam(num: number, value: unknown): string; } +export type QueryTypingsValue = 'json' | 'decimal' | 'time' | 'timestamp' | 'uuid' | 'date' | 'none'; + export interface Query { sql: string; params: unknown[]; + typings?: QueryTypingsValue[]; } export interface SQLWrapper { @@ -35,6 +40,27 @@ export function isSQLWrapper(value: unknown): value is SQLWrapper { && typeof (value as any).getSQL === 'function'; } +function prepareTyping(encoder: DriverValueEncoder): QueryTypingsValue { + if ( + encoder instanceof PgJsonb || encoder instanceof PgJson + || encoder instanceof MySqlJson + ) { + return 'json'; + } else if (encoder instanceof MySqlDecimal || encoder instanceof PgNumeric) { + return 'decimal'; + } else if (encoder instanceof PgTime || encoder instanceof MySqlTime) { + return 'time'; + } else if (encoder instanceof PgTimestamp || encoder instanceof MySqlTimestamp) { + return 'timestamp'; + } else if (encoder instanceof PgDate || encoder instanceof MySqlDate) { + return 'date'; + } else if (encoder instanceof PgUUID) { + return 'uuid'; + } else { + return 'none'; + } +} + export class SQL implements SQLWrapper { declare protected $brand: 'SQL'; @@ -42,6 +68,7 @@ export class SQL implements SQLWrapper { toQuery({ escapeName, escapeParam }: BuildQueryConfig): Query { const params: unknown[] = []; + const typings: QueryTypingsValue[] = []; const chunks = this.queryChunks.map((chunk) => { if (typeof chunk === 'string') { @@ -57,6 +84,7 @@ export class SQL implements SQLWrapper { return escapeName(chunk.table[Table.Symbol.Name]) + '.' + escapeName(chunk.name); } else if (chunk instanceof Param) { params.push(chunk.encoder.mapToDriverValue(chunk.value)); + typings.push(prepareTyping(chunk.encoder)); return escapeParam(params.length - 1, chunk.value); } else { const err = new Error('Unexpected chunk type!'); @@ -69,7 +97,7 @@ export class SQL implements SQLWrapper { .join('') .trim(); - return { sql: sqlString, params }; + return { sql: sqlString, params, typings }; } getSQL(): SQL { diff --git a/drizzle-orm/src/sqlite-core/query-builders/delete.ts b/drizzle-orm/src/sqlite-core/query-builders/delete.ts index 6430c3559..fc4c56b88 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/delete.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/delete.ts @@ -56,8 +56,9 @@ export class SQLiteDelete< return this.dialect.buildDeleteQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } prepare(): PreparedQuery<{ @@ -67,7 +68,7 @@ export class SQLiteDelete< get: TReturning extends undefined ? never : TReturning | undefined; values: TReturning extends undefined ? never : any[][]; }> { - return this.session.prepareQuery(this.toSQL(), this.config.returning); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning); } run: ReturnType['run'] = (placeholderValues) => { diff --git a/drizzle-orm/src/sqlite-core/query-builders/insert.ts b/drizzle-orm/src/sqlite-core/query-builders/insert.ts index 559360ebc..9ca2c5b7c 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/insert.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/insert.ts @@ -122,8 +122,9 @@ export class SQLiteInsert< return this.dialect.buildInsertQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } prepare(): PreparedQuery< @@ -135,7 +136,7 @@ export class SQLiteInsert< values: TReturning extends undefined ? never : any[][]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning); } run: ReturnType['run'] = (placeholderValues) => { diff --git a/drizzle-orm/src/sqlite-core/query-builders/select.ts b/drizzle-orm/src/sqlite-core/query-builders/select.ts index 03e44aeee..8089e9e4b 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/select.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/select.ts @@ -156,9 +156,9 @@ export class SQLiteSelect< return this.dialect.buildSelectQuery(this.config); } - toSQL(): Query { - const query = this.dialect.buildSelectQuery(this.config); - return this.dialect.sqlToQuery(query); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } prepare(): PreparedQuery< @@ -170,7 +170,7 @@ export class SQLiteSelect< values: any[][]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.fields); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.fields); } run: ReturnType['run'] = (placeholderValues) => { diff --git a/drizzle-orm/src/sqlite-core/query-builders/update.ts b/drizzle-orm/src/sqlite-core/query-builders/update.ts index 68abeaabe..859e8ef95 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/update.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/update.ts @@ -95,8 +95,9 @@ export class SQLiteUpdate< return this.dialect.buildUpdateQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } prepare(): PreparedQuery< @@ -108,7 +109,7 @@ export class SQLiteUpdate< values: TReturning extends undefined ? never : any[][]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning); } run: ReturnType['run'] = (placeholderValues) => { diff --git a/integration-tests/.env.example b/integration-tests/.env.example index 3411cd58f..517e6f675 100644 --- a/integration-tests/.env.example +++ b/integration-tests/.env.example @@ -1 +1,5 @@ PG_CONNECTION_STRING=postgres://postgres:postgres@localhost:5432/postgres +AWS_DATA_API_DB= +AWS_DATA_API_SECRET_ARN= +AWS_DATA_API_RESOURCE_ARN= +AWS_TEST_PROFILE= \ No newline at end of file diff --git a/integration-tests/drizzle/pg/20221207173503/migration.sql b/integration-tests/drizzle/pg/20221207173503/migration.sql index b6c0d91f6..de1ab7c10 100644 --- a/integration-tests/drizzle/pg/20221207173503/migration.sql +++ b/integration-tests/drizzle/pg/20221207173503/migration.sql @@ -1,4 +1,4 @@ -CREATE TABLE users12 ( +CREATE TABLE "users12" ( "id" serial PRIMARY KEY, "name" text NOT NULL, "email" text NOT NULL diff --git a/integration-tests/package.json b/integration-tests/package.json index 196079d89..a653e9c0f 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -9,6 +9,8 @@ "ava": { "files": [ "tests/**/*.ts", + "!tests/awsdatapi.alltypes.test.ts", + "!tests/awsdatapi.test.ts", "!tests/bun/**/*" ], "extensions": { @@ -33,8 +35,11 @@ "tsx": "^3.12.2" }, "dependencies": { + "@aws-sdk/client-rds-data": "^3.257.0", + "@aws-sdk/credential-providers": "^3.258.0", "better-sqlite3": "^7.6.2", "dockerode": "^3.3.4", + "dotenv": "^16.0.3", "drizzle-orm": "workspace:../drizzle-orm/dist", "get-port": "^6.1.2", "mysql2": "^2.3.3", diff --git a/integration-tests/tests/awsdatapi.alltypes.test.ts b/integration-tests/tests/awsdatapi.alltypes.test.ts new file mode 100644 index 000000000..81d3e32bf --- /dev/null +++ b/integration-tests/tests/awsdatapi.alltypes.test.ts @@ -0,0 +1,409 @@ +import { RDSDataClient } from '@aws-sdk/client-rds-data'; +import { fromIni } from '@aws-sdk/credential-providers'; +import anyTest, { TestFn } from 'ava'; +import * as dotenv from 'dotenv'; +import { DefaultLogger, sql } from 'drizzle-orm'; +import { AwsDataApiPgDatabase, drizzle } from 'drizzle-orm/aws-data-api/pg'; +import { + bigint, + bigserial, + boolean, + date, + decimal, + doublePrecision, + InferModel, + integer, + json, + jsonb, + numeric, + pgTable, + real, + serial, + smallint, + text, + time, + timestamp, + varchar, +} from 'drizzle-orm/pg-core'; +dotenv.config(); + +export const allColumns = pgTable('all_columns', { + sm: smallint('smallint'), + smdef: smallint('smallint_def').default(10), + int: integer('integer'), + intdef: integer('integer_def').default(10), + numeric: numeric('numeric'), + numeric2: numeric('numeric2', { precision: 5 }), + numeric3: numeric('numeric3', { scale: 2 }), + numeric4: numeric('numeric4', { precision: 5, scale: 2 }), + numericdef: numeric('numeridef').default('100'), + bigint: bigint('bigint', { mode: 'number' }), + bigintdef: bigint('bigintdef', { mode: 'number' }).default(100), + bool: boolean('boolean'), + booldef: boolean('boolean_def').default(true), + text: text('text'), + textdef: text('textdef').default('text'), + varchar: varchar('varchar'), + varchardef: varchar('varchardef').default('text'), + serial: serial('serial'), + bigserial: bigserial('bigserial', { mode: 'number' }), + decimal: decimal('decimal', { precision: 100, scale: 2 }), + decimaldef: decimal('decimaldef', { precision: 100, scale: 2 }).default('100.0'), + doublePrecision: doublePrecision('doublePrecision'), + doublePrecisiondef: doublePrecision('doublePrecisiondef').default(100.0), + real: real('real'), + realdef: real('realdef').default(100.0), + json: json<{ attr: string }>('json'), + jsondef: json<{ attr: string }>('jsondef').default({ attr: 'value' }), + jsonb: jsonb<{ attr: string }>('jsonb'), + jsonbdef: jsonb<{ attr: string }>('jsonbdef').default({ attr: 'value' }), + time: time('time'), + time2: time('time2', { precision: 6, withTimezone: true }), + timedefnow: time('timedefnow').defaultNow(), + timestamp: timestamp('timestamp'), + timestamp2: timestamp('timestamp2', { precision: 6, withTimezone: true }), + timestamp3: timestamp('timestamp3', { withTimezone: true }), + timestamp4: timestamp('timestamp4', { precision: 4 }), + timestampdef: timestamp('timestampdef').defaultNow(), + date: date('date', { mode: 'date' }), + datedef: date('datedef').defaultNow(), +}); + +interface Context { + db: AwsDataApiPgDatabase; + row: InferModel +} + +const test = anyTest as TestFn; + +test.before(async (t) => { + const ctx = t.context; + const database = process.env['AWS_DATA_API_DB']!; + const secretArn = process.env['AWS_DATA_API_SECRET_ARN']!; + const resourceArn = process.env['AWS_DATA_API_RESOURCE_ARN']!; + + const rdsClient = new RDSDataClient({ + credentials: fromIni({ profile: process.env['AWS_TEST_PROFILE'] }), + region: 'us-east-1', + }); + + ctx.db = drizzle(rdsClient, { + database, + secretArn, + resourceArn, + // logger: new DefaultLogger(), + }); + + await ctx.db.execute(sql`CREATE TABLE IF NOT EXISTS "all_columns" ( + "smallint" smallint, + "smallint_def" smallint DEFAULT 10, + "integer" integer, + "integer_def" integer DEFAULT 10, + "numeric" numeric, + "numeric2" numeric(5), + "numeric3" numeric, + "numeric4" numeric(5, 2), + "numeridef" numeric DEFAULT '100', + "bigint" bigint, + "bigintdef" bigint DEFAULT 100, + "boolean" boolean, + "boolean_def" boolean DEFAULT true, + "text" text, + "textdef" text DEFAULT 'text', + "varchar" varchar, + "varchardef" varchar DEFAULT 'text', + "serial" serial, + "bigserial" bigserial, + "decimal" numeric(100, 2), + "decimaldef" numeric(100, 2) DEFAULT '100.0', + "doublePrecision" double precision, + "doublePrecisiondef" double precision DEFAULT 100, + "real" real, + "realdef" real DEFAULT 100, + "json" json, + "jsondef" json DEFAULT '{"attr":"value"}'::json, + "jsonb" jsonb, + "jsonbdef" jsonb DEFAULT '{"attr":"value"}'::jsonb, + "time" time, + "time2" time, + "timedefnow" time DEFAULT now(), + "timestamp" timestamp, + "timestamp2" timestamp (6) with time zone, + "timestamp3" timestamp with time zone, + "timestamp4" timestamp (4), + "timestampdef" timestamp DEFAULT now(), + "date" date, + "datedef" date DEFAULT now() + )`); + + const now = new Date(); + + await ctx.db.insert(allColumns).values({ + sm: 12, + int: 22, + numeric: "1.1", + numeric2: '123.45', + numeric3: '123.45', + numeric4: '123.45', + bigint: 1578, + bool: true, + text: 'inserted_text', + varchar: 'inserted_varchar', + serial: 44, + bigserial: 63473487, + decimal: '100.1', + doublePrecision: 7384.34, + real: 73849.11, + json: { attr: 'hellohello' }, + jsonb: { attr: 'hellohello' }, + time: '11:12:00', + time2: '11:12:00', + timestamp: now, + timestamp2: now, + timestamp3: now, + timestamp4: now, + date: now, + // interval: '10 days' + }); + + const resultRows = await ctx.db.select(allColumns); + t.is(resultRows.length, 1) + + const row = resultRows[0]!; + ctx.row = row; +}); + + +test.serial('[small] serial type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.sm === 'number') + t.is(row.sm, 12) +}); + +test.serial('[small serial] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.sm === 'number') + t.is(row.smdef, 10) +}); + +test.serial('[int] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.int === 'number') + t.is(row.int, 22) +}); + +test.serial('[int] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.intdef === 'number') + t.is(row.intdef, 10) +}); + +test.serial('[numeric] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.int === 'number') + t.is(row.int, 22) +}); + +test.serial('[numeric(precision)] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.int === 'number') + t.is(row.int, 22) +}); + +test.serial('[numeric(scale)] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.int === 'number') + t.is(row.int, 22) +}); + +test.serial('[numeric(precision, scale)] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.int === 'number') + t.is(row.int, 22) +}); + +test.serial('[numeric] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.int === 'number') + t.is(row.int, 22) +}); + +test.serial('[bigint] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.bigint === 'number') + t.is(row.bigint, 1578) +}); + +test.serial('[bigint] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.bigintdef === 'number') + t.is(row.bigintdef, 100) +}); + +test.serial('[boolean] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.bool === 'boolean') + t.is(row.bool, true) +}); + +test.serial('[boolean] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.booldef === 'boolean') + t.is(row.booldef, true) +}); + +test.serial('[text] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.text === 'string') + t.is(row.text, 'inserted_text') +}); + +test.serial('[text] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.textdef === 'string') + t.is(row.textdef, 'text') +}); + +test.serial('[varchar] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.varchar === 'string') + t.is(row.varchar, 'inserted_varchar') +}); + +test.serial('[varchar] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.varchardef === 'string') + t.is(row.varchardef, 'text') +}); + +test.serial('[serial] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.serial === 'number') + t.is(row.serial, 44) +}); + +test.serial('[bigserial] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.bigserial === 'number') + t.is(row.bigserial, 63473487) +}); + +test.serial('[decimal] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.decimal === 'string') + t.is(row.decimal, '100.10') +}); + +test.serial('[decimal] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.decimaldef === 'string') + t.is(row.decimaldef, '100.00') +}); + +test.serial('[double precision] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.doublePrecision === 'number') + t.is(row.doublePrecision, 7384.34) +}); + +test.serial('[double precision] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.doublePrecisiondef === 'number') + t.is(row.doublePrecisiondef, 100.0) +}); + +test.serial('[real] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.real === 'number') + t.is(row.real, 73849.11) +}); + +test.serial('[real] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.realdef === 'number') + t.is(row.realdef, 100.0) +}); + +test.serial('[json] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.json?.attr === 'string') + t.deepEqual(row.json, { attr: 'hellohello' }) +}); + +test.serial('[json] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.jsondef?.attr === 'string') + t.deepEqual(row.jsondef, { attr: 'value' }) +}); + +test.serial('[jsonb] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.jsonb?.attr === 'string') + t.deepEqual(row.jsonb, { attr: 'hellohello' }) +}); + +test.serial('[jsonb] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.jsonbdef?.attr === 'string') + t.deepEqual(row.jsonbdef, { attr: 'value' }) +}); + +test.serial('[time] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.time === 'string') + t.assert(typeof row.time2 === 'string') + t.assert(typeof row.timedefnow === 'string') +}); + +test.serial('[timestamp] type with default', async (t) => { + const { row } = t.context; + + t.assert(row.timestamp instanceof Date) + t.assert(row.timestamp2 instanceof Date) + t.assert(row.timestamp3 instanceof Date) + t.assert(row.timestamp4 instanceof Date) + t.assert(row.timestampdef instanceof Date) +}); + +test.serial('[date] type with default', async (t) => { + const { row } = t.context; + + t.assert(row.date instanceof Date) + t.assert(typeof row.datedef === 'string') +}); + +test.after.always(async (t) => { + const ctx = t.context; + + await ctx.db.execute(sql`drop table "all_columns"`); +}); diff --git a/integration-tests/tests/awsdatapi.test.ts b/integration-tests/tests/awsdatapi.test.ts new file mode 100644 index 000000000..7124989c0 --- /dev/null +++ b/integration-tests/tests/awsdatapi.test.ts @@ -0,0 +1,648 @@ +import { RDSDataClient } from '@aws-sdk/client-rds-data'; +import { fromIni } from '@aws-sdk/credential-providers'; +import anyTest, { TestFn } from 'ava'; +import * as dotenv from 'dotenv'; +import { DefaultLogger, sql } from 'drizzle-orm'; +import { AwsDataApiPgDatabase, drizzle } from 'drizzle-orm/aws-data-api/pg'; +import { migrate } from 'drizzle-orm/aws-data-api/pg/migrator'; +import { asc, eq } from 'drizzle-orm/expressions'; +import { + alias, + boolean, + jsonb, + pgTable, + serial, + text, + timestamp, +} from 'drizzle-orm/pg-core'; +import { name, placeholder } from 'drizzle-orm/sql'; +dotenv.config(); + +const usersTable = pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: jsonb('jsonb'), + createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), +}); + +const usersMigratorTable = pgTable('users12', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), +}); +interface Context { + db: AwsDataApiPgDatabase; +} + +const test = anyTest as TestFn; + +test.before(async (t) => { + const ctx = t.context; + const database = process.env['AWS_DATA_API_DB']!; + const secretArn = process.env['AWS_DATA_API_SECRET_ARN']!; + const resourceArn = process.env['AWS_DATA_API_RESOURCE_ARN']!; + + const rdsClient = new RDSDataClient({ + credentials: fromIni({ profile: process.env['AWS_TEST_PROFILE'] }), + region: 'us-east-1', + }); + + ctx.db = drizzle(rdsClient, { + database, + secretArn, + resourceArn, + // logger: new DefaultLogger(), + }); +}); + +test.beforeEach(async (t) => { + const ctx = t.context; + await ctx.db.execute(sql`drop schema public cascade`); + await ctx.db.execute(sql`create schema public`); + await ctx.db.execute( + sql`create table users ( + id serial primary key, + name text not null, + verified boolean not null default false, + jsonb jsonb, + created_at timestamptz not null default now() + )`, + ); +}); + +test.serial('select all fields', async (t) => { + const { db } = t.context; + + const now = Date.now(); + + const insertResult = await db.insert(usersTable).values({ name: 'John' }); + + t.is(insertResult.numberOfRecordsUpdated, 1) + + const result = await db.select(usersTable); + + t.assert(result[0]!.createdAt instanceof Date); + // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 100); + t.deepEqual(result, [{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test.serial('select sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select(usersTable).fields({ + name: sql`upper(${usersTable.name})`, + }); + + t.deepEqual(users, [{ name: 'JOHN' }]); +}); + +test.serial('select typed sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select(usersTable).fields({ + name: sql`upper(${usersTable.name})`.as(), + }); + + t.deepEqual(users, [{ name: 'JOHN' }]); +}); + +test.serial('insert returning sql', async (t) => { + const { db } = t.context; + + const users = await db.insert(usersTable).values({ name: 'John' }).returning({ + name: sql`upper(${usersTable.name})`, + }); + + t.deepEqual(users, [{ name: 'JOHN' }]); +}); + +test.serial('delete returning sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')).returning({ + name: sql`upper(${usersTable.name})`, + }); + + t.deepEqual(users, [{ name: 'JOHN' }]); +}); + +test.serial('update returning sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')).returning({ + name: sql`upper(${usersTable.name})`, + }); + + t.deepEqual(users, [{ name: 'JANE' }]); +}); + +test.serial('update with returning all fields', async (t) => { + const { db } = t.context; + + const now = Date.now(); + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')).returning(); + + t.assert(users[0]!.createdAt instanceof Date); + // t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 100); + t.deepEqual(users, [{ id: 1, name: 'Jane', verified: false, jsonb: null, createdAt: users[0]!.createdAt }]); +}); + +test.serial('update with returning partial', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')).returning({ + id: usersTable.id, + name: usersTable.name, + }); + + t.deepEqual(users, [{ id: 1, name: 'Jane' }]); +}); + +test.serial('delete with returning all fields', async (t) => { + const { db } = t.context; + + const now = Date.now(); + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')).returning(); + + t.assert(users[0]!.createdAt instanceof Date); + // t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 100); + t.deepEqual(users, [{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: users[0]!.createdAt }]); +}); + +test.serial('delete with returning partial', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')).returning({ + id: usersTable.id, + name: usersTable.name, + }); + + t.deepEqual(users, [{ id: 1, name: 'John' }]); +}); + +test.serial('insert + select', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const result = await db.select(usersTable); + t.deepEqual(result, [{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + + await db.insert(usersTable).values({ name: 'Jane' }); + const result2 = await db.select(usersTable); + t.deepEqual(result2, [ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); +}); + +test.serial('json insert', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John', jsonb: ['foo', 'bar'] }); + const result = await db.select(usersTable).fields({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + }); + + t.deepEqual(result, [{ id: 1, name: 'John', jsonb: ['foo', 'bar'] }]); +}); + +test.serial('insert with overridden default values', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John', verified: true }); + const result = await db.select(usersTable); + + t.deepEqual(result, [{ id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test.serial('insert many', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values( + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ); + const result = await db.select(usersTable).fields({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }); + + t.deepEqual(result, [ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); +}); + +test.serial('insert many with returning', async (t) => { + const { db } = t.context; + + const result = await db.insert(usersTable).values( + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ) + .returning({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }); + + t.deepEqual(result, [ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); +}); + +test.serial('select with group by as field', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }); + + const result = await db.select(usersTable) + .fields({ name: usersTable.name }) + .groupBy(usersTable.name); + + t.deepEqual(result, [{ name: 'Jane' }, { name: 'John' }]); +}); + +test.serial('select with group by as sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }); + + const result = await db.select(usersTable) + .fields({ name: usersTable.name }) + .groupBy(sql`${usersTable.name}`); + + t.deepEqual(result, [{ name: 'Jane' }, { name: 'John' }]); +}); + +test.serial('select with group by as sql + column', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }); + + const result = await db.select(usersTable) + .fields({ name: usersTable.name }) + .groupBy(sql`${usersTable.name}`, usersTable.id); + + t.deepEqual(result, [{ name: 'Jane' }, { name: 'Jane' }, { name: 'John' }]); +}); + +test.serial('select with group by as column + sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }); + + const result = await db.select(usersTable) + .fields({ name: usersTable.name }) + .groupBy(usersTable.id, sql`${usersTable.name}`); + + t.deepEqual(result, [{ name: 'Jane' }, { name: 'Jane' }, { name: 'John' }]); +}); + +test.serial('select with group by complex query', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }); + + const result = await db.select(usersTable) + .fields({ name: usersTable.name }) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.name)) + .limit(1); + + t.deepEqual(result, [{ name: 'Jane' }]); +}); + +test.serial('build query', async (t) => { + const { db } = t.context; + + const query = db.select(usersTable) + .fields({ id: usersTable.id, name: usersTable.name }) + .groupBy(usersTable.id, usersTable.name) + .toSQL(); + + t.deepEqual(query, { + sql: 'select "id", "name" from "users" group by "users"."id", "users"."name"', + params: [], + // typings: [] + }); +}); + +test.serial('insert sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: sql`${'John'}` }); + const result = await db.select(usersTable).fields({ id: usersTable.id, name: usersTable.name }); + t.deepEqual(result, [{ id: 1, name: 'John' }]); +}); + +test.serial('partial join with alias', async (t) => { + const { db } = t.context; + const customerAlias = alias(usersTable, 'customer'); + + await db.insert(usersTable).values({ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }); + const result = await db + .select(usersTable) + .fields({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)); + + t.deepEqual(result, [{ + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }]); +}); + +test.serial('full join with alias', async (t) => { + const { db } = t.context; + const customerAlias = alias(usersTable, 'customer'); + + await db.insert(usersTable).values({ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }); + + const result = await db + .select(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)); + + t.deepEqual(result, [{ + users: { + id: 10, + name: 'Ivan', + verified: false, + jsonb: null, + createdAt: result[0]!.users.createdAt, + }, + customer: { + id: 11, + name: 'Hans', + verified: false, + jsonb: null, + createdAt: result[0]!.customer!.createdAt, + }, + }]); +}); + +test.serial('insert with spaces', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: sql`'Jo h n'` }); + const result = await db.select(usersTable).fields({ id: usersTable.id, name: usersTable.name }); + + t.deepEqual(result, [{ id: 1, name: 'Jo h n' }]); +}); + +test.serial('prepared statement', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const statement = db.select(usersTable) + .fields({ + id: usersTable.id, + name: usersTable.name, + }) + .prepare('statement1'); + const result = await statement.execute(); + + t.deepEqual(result, [{ id: 1, name: 'John' }]); +}); + +test.serial('prepared statement reuse', async (t) => { + const { db } = t.context; + + const stmt = db.insert(usersTable).values({ + verified: true, + name: placeholder('name'), + }).prepare('stmt2'); + + for (let i = 0; i < 10; i++) { + await stmt.execute({ name: `John ${i}` }); + } + + const result = await db.select(usersTable).fields({ + id: usersTable.id, + name: usersTable.name, + verified: usersTable.verified, + }); + + t.deepEqual(result, [ + { id: 1, name: 'John 0', verified: true }, + { id: 2, name: 'John 1', verified: true }, + { id: 3, name: 'John 2', verified: true }, + { id: 4, name: 'John 3', verified: true }, + { id: 5, name: 'John 4', verified: true }, + { id: 6, name: 'John 5', verified: true }, + { id: 7, name: 'John 6', verified: true }, + { id: 8, name: 'John 7', verified: true }, + { id: 9, name: 'John 8', verified: true }, + { id: 10, name: 'John 9', verified: true }, + ]); +}); + +test.serial('prepared statement with placeholder in .where', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const stmt = db.select(usersTable) + .fields({ + id: usersTable.id, + name: usersTable.name, + }) + .where(eq(usersTable.id, placeholder('id'))) + .prepare('stmt3'); + const result = await stmt.execute({ id: 1 }); + + t.deepEqual(result, [{ id: 1, name: 'John' }]); +}); + +test.serial('migrator', async (t) => { + const { db } = t.context; + await migrate(db, { migrationsFolder: './drizzle/pg' }); + + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + + const result = await db.select(usersMigratorTable); + + t.deepEqual(result, [{ id: 1, name: 'John', email: 'email' }]); +}); + +test.serial('insert via db.execute + select via db.execute', async (t) => { + const { db } = t.context; + + await db.execute(sql`insert into ${usersTable} (${name(usersTable.name.name)}) values (${'John'})`); + + const result = await db.execute(sql`select id, name from "users"`); + t.deepEqual(result.records![0], [{ longValue: 1 }, { stringValue: 'John' }]); +}); + +test.serial('insert via db.execute + returning', async (t) => { + const { db } = t.context; + + const inserted = await db.execute( + sql`insert into ${usersTable} (${ + name(usersTable.name.name) + }) values (${'John'}) returning ${usersTable.id}, ${usersTable.name}`, + ); + t.deepEqual(inserted.records![0], [{ longValue: 1 }, { stringValue: 'John' }]); +}); + +test.serial('insert via db.execute w/ query builder', async (t) => { + const { db } = t.context; + + const inserted = await db.execute( + db.insert(usersTable).values({ name: 'John' }).returning({ id: usersTable.id, name: usersTable.name }), + ); + t.deepEqual(inserted.records![0], [{ longValue: 1 }, { stringValue: 'John' }]); +}); + +test.serial('build query insert with onConflict do update', async (t) => { + const { db } = t.context; + + const query = db.insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onConflictDoUpdate({ target: usersTable.id, set: { name: 'John1' } }) + .toSQL(); + + t.deepEqual(query, { + sql: 'insert into "users" ("name", "jsonb") values (:1, :2) on conflict ("id") do update set "name" = :3', + params: ['John', '["foo","bar"]', 'John1'], + // typings: ['none', 'json', 'none'] + }); +}); + +test.serial('build query insert with onConflict do update / multiple columns', async (t) => { + const { db } = t.context; + + const query = db.insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onConflictDoUpdate({ target: [usersTable.id, usersTable.name], set: { name: 'John1' } }) + .toSQL(); + + t.deepEqual(query, { + sql: 'insert into "users" ("name", "jsonb") values (:1, :2) on conflict ("id","name") do update set "name" = :3', + params: ['John', '["foo","bar"]', 'John1'], + // typings: ['none', 'json', 'none'] + }); +}); + +test.serial('build query insert with onConflict do nothing', async (t) => { + const { db } = t.context; + + const query = db.insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onConflictDoNothing() + .toSQL(); + + t.deepEqual(query, { + sql: 'insert into "users" ("name", "jsonb") values (:1, :2) on conflict do nothing', + params: ['John', '["foo","bar"]'], + // typings: ['none', 'json'] + }); +}); + +test.serial('build query insert with onConflict do nothing + target', async (t) => { + const { db } = t.context; + + const query = db.insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onConflictDoNothing({ target: usersTable.id }) + .toSQL(); + + t.deepEqual(query, { + sql: 'insert into "users" ("name", "jsonb") values (:1, :2) on conflict ("id") do nothing', + params: ['John', '["foo","bar"]'], + // typings: ['none', 'json'] + }); +}); + +test.serial('insert with onConflict do update', async (t) => { + const { db } = t.context; + + await db.insert(usersTable) + .values({ name: 'John' }); + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }) + .onConflictDoUpdate({ target: usersTable.id, set: { name: 'John1' } }); + + const res = await db.select(usersTable).fields({ id: usersTable.id, name: usersTable.name }).where( + eq(usersTable.id, 1), + ); + + t.deepEqual(res, [{ id: 1, name: 'John1' }]); +}); + +test.serial('insert with onConflict do nothing', async (t) => { + const { db } = t.context; + + await db.insert(usersTable) + .values({ name: 'John' }); + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }) + .onConflictDoNothing(); + + const res = await db.select(usersTable).fields({ id: usersTable.id, name: usersTable.name }).where( + eq(usersTable.id, 1), + ); + + t.deepEqual(res, [{ id: 1, name: 'John' }]); +}); + +test.serial('insert with onConflict do nothing + target', async (t) => { + const { db } = t.context; + + await db.insert(usersTable) + .values({ name: 'John' }); + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }) + .onConflictDoNothing({ target: usersTable.id }); + + const res = await db.select(usersTable).fields({ id: usersTable.id, name: usersTable.name }).where( + eq(usersTable.id, 1), + ); + + t.deepEqual(res, [{ id: 1, name: 'John' }]); +}); + +test.after.always(async (t) => { + const ctx = t.context; + await ctx.db.execute(sql`drop table "users"`) + await ctx.db.execute(sql`drop table "drizzle"."__drizzle_migrations"`) + // await ctx.client?.end().catch(console.error); + // await ctx.pgContainer?.stop().catch(console.error); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 39438a9a3..f8ac5d2a8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,7 @@ importers: drizzle-orm: specifiers: + '@aws-sdk/client-rds-data': ^3.257.0 '@cloudflare/workers-types': ^3.18.0 '@neondatabase/serverless': ^0.1.13 '@types/better-sqlite3': ^7.6.2 @@ -43,6 +44,7 @@ importers: sql.js: ^1.8.0 sqlite3: ^5.1.2 devDependencies: + '@aws-sdk/client-rds-data': 3.257.0 '@cloudflare/workers-types': 3.18.0 '@neondatabase/serverless': 0.1.13 '@types/better-sqlite3': 7.6.3 @@ -94,6 +96,8 @@ importers: integration-tests: specifiers: + '@aws-sdk/client-rds-data': ^3.257.0 + '@aws-sdk/credential-providers': ^3.258.0 '@types/better-sqlite3': ^7.6.3 '@types/dockerode': ^3.3.14 '@types/node': ^18.11.18 @@ -103,6 +107,7 @@ importers: ava: ^5.1.0 better-sqlite3: ^7.6.2 dockerode: ^3.3.4 + dotenv: ^16.0.3 drizzle-orm: workspace:../drizzle-orm/dist get-port: ^6.1.2 mysql2: ^2.3.3 @@ -115,8 +120,11 @@ importers: uvu: ^0.5.6 zod: ^3.20.2 dependencies: + '@aws-sdk/client-rds-data': 3.257.0 + '@aws-sdk/credential-providers': 3.258.0 better-sqlite3: 7.6.2 dockerode: 3.3.4 + dotenv: 16.0.3 drizzle-orm: link:../drizzle-orm/dist get-port: 6.1.2 mysql2: 2.3.3 @@ -147,6 +155,932 @@ packages: '@jridgewell/trace-mapping': 0.3.17 dev: true + /@aws-crypto/ie11-detection/3.0.0: + resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} + dependencies: + tslib: 1.14.1 + + /@aws-crypto/sha256-browser/3.0.0: + resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} + dependencies: + '@aws-crypto/ie11-detection': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-crypto/supports-web-crypto': 3.0.0 + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-locate-window': 3.208.0 + '@aws-sdk/util-utf8-browser': 3.188.0 + tslib: 1.14.1 + + /@aws-crypto/sha256-js/3.0.0: + resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} + dependencies: + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.257.0 + tslib: 1.14.1 + + /@aws-crypto/supports-web-crypto/3.0.0: + resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} + dependencies: + tslib: 1.14.1 + + /@aws-crypto/util/3.0.0: + resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} + dependencies: + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-utf8-browser': 3.188.0 + tslib: 1.14.1 + + /@aws-sdk/abort-controller/3.257.0: + resolution: {integrity: sha512-ekWy391lOerS0ZECdhp/c+X7AToJIpfNrCPjuj3bKr+GMQYckGsYsdbm6AUD4sxBmfvuaQmVniSXWovaxwcFcQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/client-cognito-identity/3.258.0: + resolution: {integrity: sha512-xLKwJ2Q+KEyR4mRc1tNs6j2/O0SPzsD73Lbj4WRDP2Y+4JvZpn6JDihyc2OBs4JszObWOBmr2kotwHtG218WiA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.258.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/credential-provider-node': 3.258.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-signing': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8': 3.254.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/client-rds-data/3.257.0: + resolution: {integrity: sha512-9Tx61790pBKwhVFM+F0iQ0tXsykIXvuypILwepkv3p+6j5DkAIrCL/7UN1jyl1vmPZhYjCp3z96/+d91bW6sNw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.257.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/credential-provider-node': 3.257.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-signing': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8-browser': 3.188.0 + '@aws-sdk/util-utf8-node': 3.208.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + + /@aws-sdk/client-sso-oidc/3.257.0: + resolution: {integrity: sha512-yXf53Zc7DYt/4j7xGXgWaDVhE/XMDLoid5l8bOb4aDJN6kxgl5bXV/sH3DwND/fA09EQHU1W+9oe/8InVqsliw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8-browser': 3.188.0 + '@aws-sdk/util-utf8-node': 3.208.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + + /@aws-sdk/client-sso-oidc/3.258.0: + resolution: {integrity: sha512-YHQcoDsf5nnFfDJiG4uHxIg+DI90y7NpLrpx7233SeGuMNfzK2BOxHMNCZhMAxJHKB3TVpD0aN4NshVvBpcSdQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8': 3.254.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/client-sso/3.257.0: + resolution: {integrity: sha512-sD0yTTctLbjDoSV3hJem+xz9BzusmkkU/4Fts9gEs4C5NjS0YrfPAvQWE++yRzPLPR/dMhDFVCOs7voTzUhUWQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8-browser': 3.188.0 + '@aws-sdk/util-utf8-node': 3.208.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + + /@aws-sdk/client-sso/3.258.0: + resolution: {integrity: sha512-7q5GxPUD3ME/bVUfIxDZjCpNhgM/H0Cdq3sTAbrKWsxbGZDSepeysN+oxabCj9hi2TP1SENJ4gVuArejtqqfHA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8': 3.254.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/client-sts/3.257.0: + resolution: {integrity: sha512-AVNngoDGACR7xs9wTU7hrZSvMfNOGvWP/B/ieA0au3H3KDucjCZzBd3j2vYkR6Cph9dY7YkpU2Gtzn+JXD0b1g==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/credential-provider-node': 3.257.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-sdk-sts': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-signing': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8-browser': 3.188.0 + '@aws-sdk/util-utf8-node': 3.208.0 + fast-xml-parser: 4.0.11 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + + /@aws-sdk/client-sts/3.258.0: + resolution: {integrity: sha512-L6dMn5hrHgUjoY6LebmeJ3JB/xPerkVfzjel6G0ilMYSmtdAsYDe4Ik8hvTxdg06WPT9SfnrZltilESU+T8SBw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/credential-provider-node': 3.258.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-sdk-sts': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-signing': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8': 3.254.0 + fast-xml-parser: 4.0.11 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/config-resolver/3.257.0: + resolution: {integrity: sha512-jChjr8ayaXoAcUgrRr+JRIJ6bPtEoS+/xW9khpHOmrEX+uBJ7xLPfdS4e6nmxAQpbem9AsUVvf57DXhSh5/nLg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/signature-v4': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-config-provider': 3.208.0 + '@aws-sdk/util-middleware': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/credential-provider-cognito-identity/3.258.0: + resolution: {integrity: sha512-V5Z+vJ4eT4Sg0u0k1OPEPmhyixwFpS094KimC/nfcGXNQnxAkIQEKT+pD1DNenxWKBta4434l+BJUozpj64oCQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-cognito-identity': 3.258.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/credential-provider-env/3.257.0: + resolution: {integrity: sha512-GsmBi5Di6hk1JAi1iB6/LCY8o+GmlCvJoB7wuoVmXI3VxRVwptUVjuj8EtJbIrVGrF9dSuIRPCzUoSuzEzYGlg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/credential-provider-imds/3.257.0: + resolution: {integrity: sha512-UrxYkHWndy6s/bZZWH2poIyqdISTbILGTcK9tT8cFaUUrNIEFXiVESZMNNaagy0Dyy9wr80ndumxRkutYga9VA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/credential-provider-ini/3.257.0: + resolution: {integrity: sha512-69jW9/Os2zGBATQR8Urde+IlzicgJPCO/gAWpm4AYJYT5LSGc0pOuZflSXq+ZfKy3jcSoN0yOFxkoMnmZb8pzg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/credential-provider-env': 3.257.0 + '@aws-sdk/credential-provider-imds': 3.257.0 + '@aws-sdk/credential-provider-process': 3.257.0 + '@aws-sdk/credential-provider-sso': 3.257.0 + '@aws-sdk/credential-provider-web-identity': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + + /@aws-sdk/credential-provider-ini/3.258.0: + resolution: {integrity: sha512-vwy3wcIzdiBUd+kX6wKqY59JHRyOKgkPgwvd2nZt4QSQUXAldGROx48fgp/SZUEVveBpHg6Zm3IrdUWaQtAemg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/credential-provider-env': 3.257.0 + '@aws-sdk/credential-provider-imds': 3.257.0 + '@aws-sdk/credential-provider-process': 3.257.0 + '@aws-sdk/credential-provider-sso': 3.258.0 + '@aws-sdk/credential-provider-web-identity': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/credential-provider-node/3.257.0: + resolution: {integrity: sha512-yXVNOml/w4ipWiRgLWUphGwISqJQRPjALgTsRa0O+CzpaEc/0HRqM8I78VzCzjsb+QE4EP7MZej6tkEAZYgTlg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/credential-provider-env': 3.257.0 + '@aws-sdk/credential-provider-imds': 3.257.0 + '@aws-sdk/credential-provider-ini': 3.257.0 + '@aws-sdk/credential-provider-process': 3.257.0 + '@aws-sdk/credential-provider-sso': 3.257.0 + '@aws-sdk/credential-provider-web-identity': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + + /@aws-sdk/credential-provider-node/3.258.0: + resolution: {integrity: sha512-2OTFqKkfpkLZ7nkxztOIsEembl3wYhl4aAutRN5bCu8tunREWzr7v7t6X96+8CuYqcCjNYHs/9ChgFh19uokEg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/credential-provider-env': 3.257.0 + '@aws-sdk/credential-provider-imds': 3.257.0 + '@aws-sdk/credential-provider-ini': 3.258.0 + '@aws-sdk/credential-provider-process': 3.257.0 + '@aws-sdk/credential-provider-sso': 3.258.0 + '@aws-sdk/credential-provider-web-identity': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/credential-provider-process/3.257.0: + resolution: {integrity: sha512-xK8uYeNXaclaBCGrLi4z2pxPRngqLf5BM5jg2fn57zqvlL9V5gJF972FehrVBL0bfp1/laG0ZJtD2K2sapyWAw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/credential-provider-sso/3.257.0: + resolution: {integrity: sha512-I/1TQm6WruqxTTPH+Wo2o+YCLenEY0bWq97EQn+d8Cp0N7cNJUDt8BHF22dQtUzd7bvSspVK5M4qCZKAh3fhOg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-sso': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/token-providers': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + + /@aws-sdk/credential-provider-sso/3.258.0: + resolution: {integrity: sha512-2QbrpBgqabcmZkvbDLZKf8Lq99K64UsJwNkSJ+6v6+ZQQgeGIlqYaAVfrsbreCazzGcxOy0xr8DiwGrI9ZE1zQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-sso': 3.258.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/token-providers': 3.258.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/credential-provider-web-identity/3.257.0: + resolution: {integrity: sha512-Cm0uvRv4JuIbD0Kp3W0J/vwjADIyCx8HoZi5yg+QIi5nilocuTQ3ajvLeuPVSvFvdy+yaxSc5FxNXquWt7Mngw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/credential-providers/3.258.0: + resolution: {integrity: sha512-/wjbuaJCClp3Ywl50oR4AV7nbSeLTzOYLvPjFJoAXvBf7OsE1544HkJJi7Y31N/gbZKAY+ReDp0vfz3QhGdJIw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-cognito-identity': 3.258.0 + '@aws-sdk/client-sso': 3.258.0 + '@aws-sdk/client-sts': 3.258.0 + '@aws-sdk/credential-provider-cognito-identity': 3.258.0 + '@aws-sdk/credential-provider-env': 3.257.0 + '@aws-sdk/credential-provider-imds': 3.257.0 + '@aws-sdk/credential-provider-ini': 3.258.0 + '@aws-sdk/credential-provider-node': 3.258.0 + '@aws-sdk/credential-provider-process': 3.257.0 + '@aws-sdk/credential-provider-sso': 3.258.0 + '@aws-sdk/credential-provider-web-identity': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/fetch-http-handler/3.257.0: + resolution: {integrity: sha512-zOF+RzQ+wfF7tq7tGUdPcqUTh3+k2f8KCVJE07A8kCopVq4nBu4NH6Eq29Tjpwdya3YlKvE+kFssuQRRRRex+Q==} + dependencies: + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/querystring-builder': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + tslib: 2.4.1 + + /@aws-sdk/hash-node/3.257.0: + resolution: {integrity: sha512-W/USUuea5Ep3OJ2U7Ve8/5KN1YsDun2WzOFUxc1PyxXP5pW6OgC15/op0e+bmWPG851clvp5S8ZuroUr3aKi3Q==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-buffer-from': 3.208.0 + '@aws-sdk/util-utf8': 3.254.0 + tslib: 2.4.1 + + /@aws-sdk/invalid-dependency/3.257.0: + resolution: {integrity: sha512-T68SAPRNMEhpke0wlxURgogL7q0B8dfqZsSeS20BVR/lksJxLse9+pbmCDxiu1RrXoEIsEwl5rbLN+Hw8BFFYw==} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/is-array-buffer/3.201.0: + resolution: {integrity: sha512-UPez5qLh3dNgt0DYnPD/q0mVJY84rA17QE26hVNOW3fAji8W2wrwrxdacWOxyXvlxWsVRcKmr+lay1MDqpAMfg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + + /@aws-sdk/middleware-content-length/3.257.0: + resolution: {integrity: sha512-yiawbV2azm6QnMY1L2ypG8PDRdjOcEIvFmT0T7y0F49rfbKJOu21j1ONAoCkLrINK6kMqcD5JSQLVCoURxiTxQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/middleware-endpoint/3.257.0: + resolution: {integrity: sha512-RQNQe/jeVuWZtXXfcOm+e3qMFICY6ERsXUrbt0rjHgvajZCklcrRJgxJSCwrcS7Le3nl9azFPMAMj9L7uSK28g==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/signature-v4': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-config-provider': 3.208.0 + '@aws-sdk/util-middleware': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/middleware-host-header/3.257.0: + resolution: {integrity: sha512-gEi9AJdJfRfU8Qr6HK1hfhxTzyV3Giq4B/h7um99hIFAT/GCg9xiPvAOKPo6UeuiKEv3b7RpSL4s6cBvnJMJBA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/middleware-logger/3.257.0: + resolution: {integrity: sha512-8RDXW/VbMKBsXDfcCLmROZcWKyrekyiPa3J1aIaBy0tq9o4xpGoXw/lwwIrNVvISAFslb57rteup34bfn6ta6w==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/middleware-recursion-detection/3.257.0: + resolution: {integrity: sha512-rUCih6zHh8k9Edf5N5Er4s508FYbwLM0MWTD2axzlj9TjLqEQ9OKED3wHaLffXSDzodd3oTAfJCLPbWQyoZ3ZQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/middleware-retry/3.257.0: + resolution: {integrity: sha512-vDOy4PbSRW2gtgoJZ+yvgyxdlTwbZGpuv/rA2+XYxURmhPMzpmqs4o1DR37LG8O41WouI1rPzA7E+Ffo+iNWjw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/service-error-classification': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-middleware': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + tslib: 2.4.1 + uuid: 8.3.2 + + /@aws-sdk/middleware-sdk-sts/3.257.0: + resolution: {integrity: sha512-d6IJCLRi3O2tm4AFK60WNhIwmMmspj1WzKR1q1TaoPzoREPG2xg+Am18wZBRkCyYuRPPrbizmkvAmAJiUolMAw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/middleware-signing': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/signature-v4': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/middleware-serde/3.257.0: + resolution: {integrity: sha512-/JasfXPWFq24mnCrx9fxW/ISBSp07RJwhsF14qzm8Qy3Z0z470C+QRM6otTwAkYuuVt1wuLjja5agq3Jtzq7dQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/middleware-signing/3.257.0: + resolution: {integrity: sha512-hCH3D83LHmm6nqmtNrGTWZCVjsQXrGHIXbd17/qrw7aPFvcAhsiiCncGFP+XsUXEKa2ZqcSNMUyPrx69ofNRZQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/signature-v4': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-middleware': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/middleware-stack/3.257.0: + resolution: {integrity: sha512-awg2F0SvwACBaw4HIObK8pQGfSqAc4Vy+YFzWSfZNVC35oRO6RsRdKHVU99lRC0LrT2Ptmfghl2DMPSrRDbvlQ==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + + /@aws-sdk/middleware-user-agent/3.257.0: + resolution: {integrity: sha512-37rt75LZyD0UWpbcFuxEGqwF3DZKSixQPl7AsDe6q3KtrO5gGQB+diH5vbY0txNNYyv5IK9WMwvY73mVmoWRmw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/node-config-provider/3.257.0: + resolution: {integrity: sha512-IfGF7+cU0PyB7RpHlgc445ZAUZDWn4ij2HTB6N+xULwFw2TxnyQ2tvo3Gp5caW9VlJ3eXE9wFrynv+JXUIH7Bg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/node-http-handler/3.257.0: + resolution: {integrity: sha512-8KnWHVVwaGKyTlkTU9BSOAiSovNDoagxemU2l10QqBbzUCVpljCUMUkABEGRJ1yoQCl6DJ7RtNkAyZ8Ne/E15A==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/abort-controller': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/querystring-builder': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/property-provider/3.257.0: + resolution: {integrity: sha512-3rUbRAcF0GZ5PhDiXhS4yREfZ5hOEtvYEa9S/19OdM5eoypOaLU5XnFcCKfnccSP8SkdgpJujzxOMRWNWadlAQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/protocol-http/3.257.0: + resolution: {integrity: sha512-xt7LGOgZIvbLS3418AYQLacOqx+mo5j4mPiIMz7f6AaUg+/fBUgESVsncKDqxbEJVwwCXSka8Ca0cntJmoeMSw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/querystring-builder/3.257.0: + resolution: {integrity: sha512-mZHWLP7XIkzx1GIXO5WfX/iJ+aY9TWs02RE9FkdL2+by0HEMR65L3brQTbU1mIBJ7BjaPwYH24dljUOSABX7yg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-uri-escape': 3.201.0 + tslib: 2.4.1 + + /@aws-sdk/querystring-parser/3.257.0: + resolution: {integrity: sha512-UDrE1dEwWrWT8dG2VCrGYrPxCWOkZ1fPTPkjpkR4KZEdQDZBqU5gYZF2xPj8Nz7pjQVHFuW2wFm3XYEk56GEjg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/service-error-classification/3.257.0: + resolution: {integrity: sha512-FAyR0XsueGkkqDtkP03cTJQk52NdQ9sZelLynmmlGPUP75LApRPvFe1riKrou6+LsDbwVNVffj6mbDfIcOhaOw==} + engines: {node: '>=14.0.0'} + + /@aws-sdk/shared-ini-file-loader/3.257.0: + resolution: {integrity: sha512-HNjC1+Wx3xHiJc+CP14GhIdVhfQGSjroAsWseRxAhONocA9Fl1ZX4hx7+sA5c9nOoMVOovi6ivJ/6lCRPTDRrQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/signature-v4/3.257.0: + resolution: {integrity: sha512-aLQQN59X/D0+ShzPD3Anj5ntdMA/RFeNLOUCDyDvremViGi6yxUS98usQ/8bG5Rq0sW2GGMdbFUFmrDvqdiqEQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/is-array-buffer': 3.201.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-hex-encoding': 3.201.0 + '@aws-sdk/util-middleware': 3.257.0 + '@aws-sdk/util-uri-escape': 3.201.0 + '@aws-sdk/util-utf8': 3.254.0 + tslib: 2.4.1 + + /@aws-sdk/smithy-client/3.257.0: + resolution: {integrity: sha512-Vy/en+llpslHG6WZ2yuN+On6u7p2hROEURwAST/lpReAwBETjbsxylkWvP8maeGKQ54u9uC6lIZAOJut2I3INw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/token-providers/3.257.0: + resolution: {integrity: sha512-Ysd1dpWiI2oBOrJpkSJkgPsY0dwMtavIBzF3d5JYN1HCl14Aqc2jcNqBjD+7nEeL6CHXcFeyB7jmCDqiuP0V3A==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-sso-oidc': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + + /@aws-sdk/token-providers/3.258.0: + resolution: {integrity: sha512-5Lme7XHlBC/iPHQOr5V+LdxHnwg2a7mhRYVy42a8OOKHN2ronDo/Wnujw2s4BOaEnlqS8OSV84bZ0bWxVYuvKw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-sso-oidc': 3.258.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/types/3.257.0: + resolution: {integrity: sha512-LmqXuBQBGeaGi/3Rp7XiEX1B5IPO2UUfBVvu0wwGqVsmstT0SbOVDZGPmxygACbm64n+PRx3uTSDefRfoiWYZg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + + /@aws-sdk/url-parser/3.257.0: + resolution: {integrity: sha512-Qe/AcFe/NFZHa6cN2afXEQn9ehXxh57dWGdRjfjd2lQqNV4WW1R2pl2Tm1ZJ1dwuCNLJi4NHLMk8lrD3QQ8rdg==} + dependencies: + '@aws-sdk/querystring-parser': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/util-base64/3.208.0: + resolution: {integrity: sha512-PQniZph5A6N7uuEOQi+1hnMz/FSOK/8kMFyFO+4DgA1dZ5pcKcn5wiFwHkcTb/BsgVqQa3Jx0VHNnvhlS8JyTg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/util-buffer-from': 3.208.0 + tslib: 2.4.1 + + /@aws-sdk/util-body-length-browser/3.188.0: + resolution: {integrity: sha512-8VpnwFWXhnZ/iRSl9mTf+VKOX9wDE8QtN4bj9pBfxwf90H1X7E8T6NkiZD3k+HubYf2J94e7DbeHs7fuCPW5Qg==} + dependencies: + tslib: 2.4.1 + + /@aws-sdk/util-body-length-node/3.208.0: + resolution: {integrity: sha512-3zj50e5g7t/MQf53SsuuSf0hEELzMtD8RX8C76f12OSRo2Bca4FLLYHe0TZbxcfQHom8/hOaeZEyTyMogMglqg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + + /@aws-sdk/util-buffer-from/3.208.0: + resolution: {integrity: sha512-7L0XUixNEFcLUGPeBF35enCvB9Xl+K6SQsmbrPk1P3mlV9mguWSDQqbOBwY1Ir0OVbD6H/ZOQU7hI/9RtRI0Zw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/is-array-buffer': 3.201.0 + tslib: 2.4.1 + + /@aws-sdk/util-config-provider/3.208.0: + resolution: {integrity: sha512-DSRqwrERUsT34ug+anlMBIFooBEGwM8GejC7q00Y/9IPrQy50KnG5PW2NiTjuLKNi7pdEOlwTSEocJE15eDZIg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + + /@aws-sdk/util-defaults-mode-browser/3.257.0: + resolution: {integrity: sha512-nkfK+MNacVd3Px/fcAvU0hDeh+r7d+RLLt3sJ5Zc0gGd+i3OQEP58V8QzR9PYMvUvSvGQP16fQVQHSbRZtuWyQ==} + engines: {node: '>= 10.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/types': 3.257.0 + bowser: 2.11.0 + tslib: 2.4.1 + + /@aws-sdk/util-defaults-mode-node/3.257.0: + resolution: {integrity: sha512-qsIb7aPbGFcKbBGoAQmlzv1gMcscgbpfrRh4rgNqkJXVbJ52Ql6+vXXfBmlWaBho0fcsNh5XnYu1fzdCuu+N7g==} + engines: {node: '>= 10.0.0'} + dependencies: + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/credential-provider-imds': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/util-endpoints/3.257.0: + resolution: {integrity: sha512-3bvmRn5XGYzPPWjLuvHBKdJOb+fijnb8Ungu9bfXnTYFsng/ndHUWeHC22O/p8w3OWoRYUIMaZHxdxe27BFozg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/util-hex-encoding/3.201.0: + resolution: {integrity: sha512-7t1vR1pVxKx0motd3X9rI3m/xNp78p3sHtP5yo4NP4ARpxyJ0fokBomY8ScaH2D/B+U5o9ARxldJUdMqyBlJcA==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + + /@aws-sdk/util-locate-window/3.208.0: + resolution: {integrity: sha512-iua1A2+P7JJEDHVgvXrRJSvsnzG7stYSGQnBVphIUlemwl6nN5D+QrgbjECtrbxRz8asYFHSzhdhECqN+tFiBg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + + /@aws-sdk/util-middleware/3.257.0: + resolution: {integrity: sha512-F9ieon8B8eGVs5tyZtAIG3DZEObDvujkspho0qRbUTHUosM0ylJLsMU800fmC/uRHLRrZvb/RSp59+kNDwSAMw==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + + /@aws-sdk/util-retry/3.257.0: + resolution: {integrity: sha512-l9TOsOAYtZxwW3q5fQKW4rsD9t2HVaBfQ4zBamHkNTfB4vBVvCnz4oxkvSvA2MlxCA6am+K1K/oj917Tpqk53g==} + engines: {node: '>= 14.0.0'} + dependencies: + '@aws-sdk/service-error-classification': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/util-uri-escape/3.201.0: + resolution: {integrity: sha512-TeTWbGx4LU2c5rx0obHeDFeO9HvwYwQtMh1yniBz00pQb6Qt6YVOETVQikRZ+XRQwEyCg/dA375UplIpiy54mA==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + + /@aws-sdk/util-user-agent-browser/3.257.0: + resolution: {integrity: sha512-YdavWK6/8Cw6mypEgysGGX/dT9p9qnzFbnN5PQsUY+JJk2Nx8fKFydjGiQ+6rWPeW17RAv9mmbboh9uPVWxVlw==} + dependencies: + '@aws-sdk/types': 3.257.0 + bowser: 2.11.0 + tslib: 2.4.1 + + /@aws-sdk/util-user-agent-node/3.257.0: + resolution: {integrity: sha512-fOHh80kiVomUkABmOv3ZxB/SNLnOPAja7uhQmGWfKHXBkcxTVfWO2KBs5vzU5qhVZA0c1zVEvZPcBdRsonnhlw==} + engines: {node: '>=14.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + dependencies: + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + + /@aws-sdk/util-utf8-browser/3.188.0: + resolution: {integrity: sha512-jt627x0+jE+Ydr9NwkFstg3cUvgWh56qdaqAMDsqgRlKD21md/6G226z/Qxl7lb1VEW2LlmCx43ai/37Qwcj2Q==} + dependencies: + tslib: 2.4.1 + + /@aws-sdk/util-utf8-node/3.208.0: + resolution: {integrity: sha512-jKY87Acv0yWBdFxx6bveagy5FYjz+dtV8IPT7ay1E2WPWH1czoIdMAkc8tSInK31T6CRnHWkLZ1qYwCbgRfERQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/util-buffer-from': 3.208.0 + tslib: 2.4.1 + + /@aws-sdk/util-utf8/3.254.0: + resolution: {integrity: sha512-14Kso/eIt5/qfIBmhEL9L1IfyUqswjSTqO2mY7KOzUZ9SZbwn3rpxmtkhmATkRjD7XIlLKaxBkI7tU9Zjzj8Kw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/util-buffer-from': 3.208.0 + tslib: 2.4.1 + /@babel/code-frame/7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} @@ -1114,6 +2048,9 @@ packages: resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} dev: true + /bowser/2.11.0: + resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + /brace-expansion/1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -1574,6 +2511,11 @@ packages: engines: {node: '>=10'} dev: true + /dotenv/16.0.3: + resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} + engines: {node: '>=12'} + dev: false + /dprint/0.32.2: resolution: {integrity: sha512-cGKnZonCFQkcNbptAtJXlzUOqyiyYoD9pINepJ9PvkFi8iwMLChQDSjhMeqT3DDQf5Rof3pYA5LI/bafPpPknQ==} hasBin: true @@ -2214,6 +3156,12 @@ packages: micromatch: 4.0.5 dev: true + /fast-xml-parser/4.0.11: + resolution: {integrity: sha512-4aUg3aNRR/WjQAcpceODG1C3x3lFANXRo8+1biqfieHmg9pyMt7qB4lQV/Ta6sJCTbA5vfD8fnA8S54JATiFUA==} + hasBin: true + dependencies: + strnum: 1.0.5 + /fastq/1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: @@ -3699,6 +4647,9 @@ packages: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} + /strnum/1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + /supertap/3.0.1: resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -3805,9 +4756,11 @@ packages: hasBin: true dev: true + /tslib/1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + /tslib/2.4.1: resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} - dev: true /tsx/3.12.2: resolution: {integrity: sha512-ykAEkoBg30RXxeOMVeZwar+JH632dZn9EUJVyJwhfag62k6UO/dIyJEV58YuLF6e5BTdV/qmbQrpkWqjq9cUnQ==} @@ -3951,6 +4904,10 @@ packages: /util-deprecate/1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + /uuid/8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + /uuid/9.0.0: resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} hasBin: true