From cc673c9a7885351082020e360630eab5db78c652 Mon Sep 17 00:00:00 2001 From: Emily Morgan Date: Fri, 21 Jun 2024 10:04:54 +0200 Subject: [PATCH] Make CLI backwards compatible with non pgroll branches (#1494) Signed-off-by: Alexis Rico Co-authored-by: Alexis Rico Co-authored-by: Andrew Farries --- .changeset/quick-buckets-confess.md | 5 + cli/package.json | 3 + cli/src/base.ts | 36 +- cli/src/commands/branch/create.ts | 5 +- cli/src/commands/branch/delete.ts | 2 +- cli/src/commands/branch/list.ts | 2 +- cli/src/commands/dbs/delete.ts | 2 +- cli/src/commands/dbs/list.ts | 4 +- cli/src/commands/dbs/rename.ts | 5 +- cli/src/commands/diff/index.ts | 18 +- cli/src/commands/import/csv.ts | 195 +- cli/src/commands/init/index.ts | 4 +- cli/src/commands/pull/index.ts | 32 +- cli/src/commands/pull/pull.test.ts | 4 +- cli/src/commands/push/index.ts | 56 +- cli/src/commands/push/push.test.ts | 12 +- cli/src/commands/random-data/index.ts | 8 +- cli/src/commands/rebase/index.ts | 62 +- cli/src/commands/schema/edit-old.ts | 917 ++++++++ cli/src/commands/schema/edit.test.ts | 895 ++++++++ cli/src/commands/schema/edit.ts | 1710 ++++++++------ cli/src/commands/schema/upload.ts | 12 +- cli/src/commands/workspace/create.ts | 2 +- cli/src/commands/workspace/delete.ts | 2 +- cli/src/migrations/files.ts | 2 +- cli/src/migrations/pgroll.ts | 423 +++- cli/src/utils/compareSchema.ts | 129 ++ packages/client/src/api/client.test.ts | 26 + packages/client/src/api/client.ts | 2028 +---------------- packages/client/src/util/types.ts | 8 + packages/importer/src/importer.ts | 14 +- .../test/drizzle.test.ts | 18 +- pnpm-lock.yaml | 1791 ++++++++++----- test/integration/query.test.ts | 14 +- test/integration/smoke.test.ts | 95 +- test/utils/setup.ts | 27 +- 36 files changed, 5020 insertions(+), 3548 deletions(-) create mode 100644 .changeset/quick-buckets-confess.md create mode 100644 cli/src/commands/schema/edit-old.ts create mode 100644 cli/src/commands/schema/edit.test.ts create mode 100644 cli/src/utils/compareSchema.ts create mode 100644 packages/client/src/api/client.test.ts diff --git a/.changeset/quick-buckets-confess.md b/.changeset/quick-buckets-confess.md new file mode 100644 index 000000000..47b1268cc --- /dev/null +++ b/.changeset/quick-buckets-confess.md @@ -0,0 +1,5 @@ +--- +'@xata.io/client': minor +--- + +[Breaking] Update `XataApiClient` to use unified parameters diff --git a/cli/package.json b/cli/package.json index 6bdd1e245..954edd994 100644 --- a/cli/package.json +++ b/cli/package.json @@ -40,6 +40,7 @@ "enquirer": "^2.4.1", "env-editor": "^1.1.0", "ini": "^4.1.3", + "lodash.keyby": "^4.6.0", "lodash.compact": "^3.0.1", "lodash.get": "^4.4.2", "lodash.set": "^4.3.2", @@ -51,6 +52,7 @@ "text-table": "^0.2.0", "tslib": "^2.6.3", "tmp": "^0.2.3", + "type-fest": "^4.18.1", "which": "^4.0.0", "zod": "^3.23.8" }, @@ -59,6 +61,7 @@ "@types/babel__core": "^7.20.5", "@types/lodash.compact": "^3.0.9", "@types/lodash.get": "^4.4.9", + "@types/lodash.keyby": "^4.6.9", "@types/lodash.set": "^4.3.9", "@types/relaxed-json": "^1.0.4", "@types/text-table": "^0.2.5", diff --git a/cli/src/base.ts b/cli/src/base.ts index 4accc7e31..7249532cd 100644 --- a/cli/src/base.ts +++ b/cli/src/base.ts @@ -281,7 +281,7 @@ export abstract class BaseCommand extends Command { message: 'New workspace name' }); if (!name) return this.error('No workspace name provided'); - const workspace = await xata.api.workspaces.createWorkspace({ data: { name } }); + const workspace = await xata.api.workspaces.createWorkspace({ body: { name } }); return workspace.id; } else if (workspaces.workspaces.length === 1) { const workspace = workspaces.workspaces[0].id; @@ -309,7 +309,9 @@ export abstract class BaseCommand extends Command { options: { allowCreate?: boolean } = {} ): Promise<{ name: string; region: string }> { const xata = await this.getXataClient(); - const { databases: dbs = [] } = await xata.api.database.getDatabaseList({ workspace }); + const { databases: dbs = [] } = await xata.api.databases.getDatabaseList({ + pathParams: { workspaceId: workspace } + }); if (dbs.length > 0) { const choices = dbs.map((db) => ({ @@ -355,7 +357,9 @@ export abstract class BaseCommand extends Command { } = {} ): Promise { const xata = await this.getXataClient(); - const { branches = [] } = await xata.api.branches.getBranchList({ workspace, region, database }); + const { branches = [] } = await xata.api.branch.getBranchList({ + pathParams: { workspace, region, dbName: database } + }); const EMPTY_CHOICE = '$empty'; const CREATE_CHOICE = '$create'; @@ -421,7 +425,7 @@ export abstract class BaseCommand extends Command { ); if (!name) return this.error('No database name provided'); - const { regions } = await xata.api.database.listRegions({ workspace }); + const { regions } = await xata.api.databases.listRegions({ pathParams: { workspaceId: workspace } }); const { region } = await this.prompt( { type: 'select', @@ -434,7 +438,10 @@ export abstract class BaseCommand extends Command { ); if (!region) return this.error('No region selected'); - const result = await xata.api.database.createDatabase({ workspace, database: name, data: { region } }); + const result = await xata.api.databases.createDatabase({ + pathParams: { workspaceId: workspace, dbName: name }, + body: { region } + }); return { name: result.databaseName, region }; } @@ -455,9 +462,12 @@ export abstract class BaseCommand extends Command { }); if (!from) { - await xata.api.branches.createBranch({ workspace, region, database, branch: name }); + await xata.api.branch.createBranch({ pathParams: { workspace, region, dbBranchName: `${database}:${name}` } }); } else { - await xata.api.branches.createBranch({ workspace, region, database, branch: name, from }); + await xata.api.branch.createBranch({ + pathParams: { workspace, region, dbBranchName: `${database}:${name}` }, + body: { from } + }); } return name; @@ -566,11 +576,8 @@ export abstract class BaseCommand extends Command { async deploySchema(workspace: string, region: string, database: string, branch: string, schema: Schemas.Schema) { const xata = await this.getXataClient(); const compare = await xata.api.migrations.compareBranchWithUserSchema({ - workspace, - region, - database, - branch, - schema + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + body: { schema } }); if (compare.edits.operations.length === 0) { @@ -587,7 +594,10 @@ export abstract class BaseCommand extends Command { }); if (!confirm) return this.exit(1); - await xata.api.migrations.applyBranchSchemaEdit({ workspace, region, database, branch, edits: compare.edits }); + await xata.api.migrations.applyBranchSchemaEdit({ + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + body: { edits: compare.edits } + }); } } diff --git a/cli/src/commands/branch/create.ts b/cli/src/commands/branch/create.ts index 3dac4c9c4..6d25500b7 100644 --- a/cli/src/commands/branch/create.ts +++ b/cli/src/commands/branch/create.ts @@ -32,7 +32,10 @@ export default class BranchCreate extends BaseCommand { const { from } = flags; try { - const result = await xata.api.branches.createBranch({ workspace, region, database, branch, from }); + const result = await xata.api.branch.createBranch({ + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + body: { from } + }); if (this.jsonEnabled()) return result; diff --git a/cli/src/commands/branch/delete.ts b/cli/src/commands/branch/delete.ts index 1f865dfed..1b230a658 100644 --- a/cli/src/commands/branch/delete.ts +++ b/cli/src/commands/branch/delete.ts @@ -37,7 +37,7 @@ export default class BranchDelete extends BaseCommand { if (!confirm) return this.exit(1); if (confirm !== branch) return this.error('The branch name did not match'); - await xata.api.branches.deleteBranch({ workspace, region, database, branch }); + await xata.api.branch.deleteBranch({ pathParams: { workspace, region, dbBranchName: `${database}:${branch}` } }); if (this.jsonEnabled()) return {}; diff --git a/cli/src/commands/branch/list.ts b/cli/src/commands/branch/list.ts index 2c32536e3..f1d3c603c 100644 --- a/cli/src/commands/branch/list.ts +++ b/cli/src/commands/branch/list.ts @@ -19,7 +19,7 @@ export default class BranchList extends BaseCommand { const { workspace, region, database } = await this.getParsedDatabaseURL(flags.db); const xata = await this.getXataClient(); - const { branches } = await xata.api.branches.getBranchList({ workspace, region, database }); + const { branches } = await xata.api.branch.getBranchList({ pathParams: { workspace, region, dbName: database } }); if (this.jsonEnabled()) return branches; diff --git a/cli/src/commands/dbs/delete.ts b/cli/src/commands/dbs/delete.ts index 708a92bd4..a7a3302ff 100644 --- a/cli/src/commands/dbs/delete.ts +++ b/cli/src/commands/dbs/delete.ts @@ -39,7 +39,7 @@ export default class DatabasesDelete extends BaseCommand if (!confirm) return this.exit(1); if (confirm !== database) return this.error('The database name did not match'); - await xata.api.database.deleteDatabase({ workspace, database }); + await xata.api.databases.deleteDatabase({ pathParams: { workspaceId: workspace, dbName: database } }); if (this.jsonEnabled()) return {}; diff --git a/cli/src/commands/dbs/list.ts b/cli/src/commands/dbs/list.ts index bbcfdf8d5..104f7c5bf 100644 --- a/cli/src/commands/dbs/list.ts +++ b/cli/src/commands/dbs/list.ts @@ -25,7 +25,9 @@ export default class DatabasesList extends BaseCommand { (await this.getWorkspace()); const xata = await this.getXataClient(); - const { databases: dbs = [] } = await xata.api.database.getDatabaseList({ workspace }); + const { databases: dbs = [] } = await xata.api.databases.getDatabaseList({ + pathParams: { workspaceId: workspace } + }); if (this.jsonEnabled()) return dbs; diff --git a/cli/src/commands/dbs/rename.ts b/cli/src/commands/dbs/rename.ts index 0ce21e160..244ae83d2 100644 --- a/cli/src/commands/dbs/rename.ts +++ b/cli/src/commands/dbs/rename.ts @@ -43,7 +43,10 @@ export default class DatabasesRename extends BaseCommand if (!confirm) return this.exit(1); if (confirm !== database) return this.error('The database name did not match'); - await xata.api.database.renameDatabase({ workspace, database, newName }); + await xata.api.databases.renameDatabase({ + pathParams: { workspaceId: workspace, dbName: database }, + body: { newName } + }); if (this.jsonEnabled()) return {}; diff --git a/cli/src/commands/diff/index.ts b/cli/src/commands/diff/index.ts index a171ed9a6..e3d6ca7d4 100644 --- a/cli/src/commands/diff/index.ts +++ b/cli/src/commands/diff/index.ts @@ -2,6 +2,7 @@ import { Args } from '@oclif/core'; import { BaseCommand } from '../../base.js'; import { getLocalMigrationFiles } from '../../migrations/files.js'; import { buildMigrationDiff } from '../../utils/diff.js'; +import compact from 'lodash.compact'; export default class Diff extends BaseCommand { static description = 'Compare two local or remote branches'; @@ -34,24 +35,17 @@ export default class Diff extends BaseCommand { this.info(`Diff command is experimental, use with caution`); const localMigrationFiles = await getLocalMigrationFiles(); - const schemaOperations = localMigrationFiles.flatMap((migrationFile) => migrationFile.operations); + const schemaOperations = compact(localMigrationFiles.flatMap((migrationFile) => migrationFile.operations)); const apiRequest = args.branch && args.base ? xata.api.migrations.compareBranchSchemas({ - workspace, - region, - database, - branch: args.branch, - compare: args.base + pathParams: { workspace, region, dbBranchName: `${database}:${args.branch}`, branchName: args.base }, + body: {} }) : xata.api.migrations.compareBranchWithUserSchema({ - workspace, - region, - database, - branch, - schema: { tables: [] }, - schemaOperations: schemaOperations as any + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + body: { schema: { tables: [] }, schemaOperations } }); const { diff --git a/cli/src/commands/import/csv.ts b/cli/src/commands/import/csv.ts index 5ee9d6fbc..a61ba4574 100644 --- a/cli/src/commands/import/csv.ts +++ b/cli/src/commands/import/csv.ts @@ -5,7 +5,14 @@ import { importColumnTypes } from '@xata.io/importer'; import { open, writeFile } from 'fs/promises'; import { BaseCommand } from '../../base.js'; import { enumFlag } from '../../utils/oclif.js'; -import { getBranchDetailsWithPgRoll } from '../../migrations/pgroll.js'; +import { + getBranchDetailsWithPgRoll, + isBranchPgRollEnabled, + waitForMigrationToFinish, + xataColumnTypeToPgRollComment +} from '../../migrations/pgroll.js'; +import { compareSchemas } from '../../utils/compareSchema.js'; +import keyBy from 'lodash.keyby'; const ERROR_CONSOLE_LOG_LIMIT = 200; const ERROR_LOG_FILE = 'errors.log'; @@ -23,6 +30,8 @@ const bufferEncodings: BufferEncoding[] = [ 'hex' ]; +const INTERNAL_COLUMNS_PGROLL = ['xata_id', 'xata_createdat', 'xata_updatedat', 'xata_version']; + export default class ImportCSV extends BaseCommand { static description = 'Import a CSV file'; @@ -80,6 +89,8 @@ export default class ImportCSV extends BaseCommand { file: Args.string({ description: 'The file to be imported', required: true }) }; + #pgrollEnabled: boolean = false; + async run(): Promise { const { args, flags } = await this.parseCommand(); const { file } = args; @@ -128,6 +139,9 @@ export default class ImportCSV extends BaseCommand { throw new Error(`Failed to parse CSV file ${parseResults.errors.join(' ')}`); } + const details = await getBranchDetailsWithPgRoll(xata, { workspace, region, database, branch }); + this.#pgrollEnabled = isBranchPgRollEnabled(details); + const { columns } = parseResults; await this.migrateSchema({ table, columns, create }); @@ -144,12 +158,32 @@ export default class ImportCSV extends BaseCommand { if (!parseResults.success) { throw new Error('Failed to parse CSV file'); } - const batchRows = parseResults.data.map(({ data }) => data); + const batchRows = () => { + if (this.#pgrollEnabled) { + const res = parseResults.data.map(({ data }) => { + const formattedRow: { [k: string]: any } = {}; + const keys = Object.keys(data); + for (const key of keys) { + if (INTERNAL_COLUMNS_PGROLL.includes(key) && key !== 'xata_id') continue; + formattedRow[key] = data[key]; + } + return formattedRow; + }); + return res; + } else { + return parseResults.data.map(({ data }) => data); + } + }; const importResult = await xata.import.importBatch( { workspace, region, database, branch }, - { columns: parseResults.columns, table, batchRows } + { + columns: this.#pgrollEnabled + ? parseResults.columns.filter(({ name }) => name === 'xata_id' || !INTERNAL_COLUMNS_PGROLL.includes(name)) + : parseResults.columns, + table, + batchRows: batchRows() + } ); - await xata.import.importFiles( { database, branch, region, workspace: workspace }, { @@ -218,52 +252,133 @@ export default class ImportCSV extends BaseCommand { { name: table, columns: columns.filter((c) => c.name !== 'id') } ] }; - const { edits } = await xata.api.migrations.compareBranchWithUserSchema({ - workspace, - region, - database, - branch: 'main', - schema: newSchema - }); - if (edits.operations.length > 0) { - const destructiveOperations = edits.operations - .map((op) => { - if (!('removeColumn' in op)) return undefined; - return op.removeColumn.column; - }) - .filter((x) => x !== undefined); - - if (destructiveOperations.length > 0) { - const { destructiveConfirm } = await this.prompt( + + if (this.#pgrollEnabled) { + const { edits } = compareSchemas( + {}, + { + tables: { + [table]: { + name: table, + xataCompatible: false, + columns: keyBy( + columns + .filter((c) => !INTERNAL_COLUMNS_PGROLL.includes(c.name as any)) + .map((c) => { + return { + name: c.name, + type: c.type, + nullable: c.notNull !== false, + default: c.defaultValue ?? null, + unique: c.unique, + comment: xataColumnTypeToPgRollComment(c) + }; + }), + 'name' + ) + } + } + } + ); + + if (edits.length > 0) { + const destructiveOperations = edits + .map((op) => { + if (!('drop_column' in op)) return undefined; + return op.drop_column.column; + }) + .filter((x) => x !== undefined); + + if (destructiveOperations.length > 0) { + const { destructiveConfirm } = await this.prompt( + { + type: 'confirm', + name: 'destructiveConfirm', + message: `WARNING: The following columns will be removed and you will lose data. ${destructiveOperations.join( + ', ' + )}. \nDo you want to continue?` + }, + create + ); + if (!destructiveConfirm) { + process.exit(1); + } + } + + const doesTableExist = existingSchema.tables.find((t) => t.name === table); + const { applyMigrations } = await this.prompt( { type: 'confirm', - name: 'destructiveConfirm', - message: `WARNING: The following columns will be removed and you will lose data. ${destructiveOperations.join( - ', ' - )}. \nDo you want to continue?` + name: 'applyMigrations', + message: `Do you want to ${doesTableExist ? 'update' : 'create'} table: ${table} with columns ${columns + .map((c) => c.name) + .join(', ')}?` }, create ); - if (!destructiveConfirm) { + if (!applyMigrations) { process.exit(1); } + + const { jobID } = await xata.api.migrations.applyMigration({ + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + body: { operations: edits, adaptTables: true } + }); + await waitForMigrationToFinish(xata.api, workspace, region, database, branch, jobID); } + } else { + const { edits } = await xata.api.migrations.compareBranchWithUserSchema({ + pathParams: { workspace, region, dbBranchName: `${database}:main` }, + body: { schema: newSchema } + }); - const doesTableExist = existingSchema.tables.find((t) => t.name === table); - const { applyMigrations } = await this.prompt( - { - type: 'confirm', - name: 'applyMigrations', - message: `Do you want to ${doesTableExist ? 'update' : 'create'} table: ${table} with columns ${columns - .map((c) => c.name) - .join(', ')}?` - }, - create - ); - if (!applyMigrations) { - process.exit(1); + if (edits.operations.length > 0) { + const destructiveOperations = edits.operations + .map((op) => { + if (!('removeColumn' in op)) return undefined; + return op.removeColumn.column; + }) + .filter((x) => x !== undefined); + + if (destructiveOperations.length > 0) { + const { destructiveConfirm } = await this.prompt( + { + type: 'confirm', + name: 'destructiveConfirm', + message: `WARNING: The following columns will be removed and you will lose data. ${destructiveOperations.join( + ', ' + )}. \nDo you want to continue?` + }, + create + ); + if (!destructiveConfirm) { + process.exit(1); + } + } + + const doesTableExist = existingSchema.tables.find((t) => t.name === table); + const { applyMigrations } = await this.prompt( + { + type: 'confirm', + name: 'applyMigrations', + message: `Do you want to ${doesTableExist ? 'update' : 'create'} table: ${table} with columns ${columns + .map((c) => c.name) + .join(', ')}?` + }, + create + ); + if (!applyMigrations) { + process.exit(1); + } + await xata.api.migrations.applyBranchSchemaEdit({ + pathParams: { + workspace, + region, + dbBranchName: `${database}:${branch}` + }, + body: { edits } + }); } - await xata.api.migrations.applyBranchSchemaEdit({ workspace, region, database, branch, edits }); } } } diff --git a/cli/src/commands/init/index.ts b/cli/src/commands/init/index.ts index a26e643f3..8cf58939d 100644 --- a/cli/src/commands/init/index.ts +++ b/cli/src/commands/init/index.ts @@ -187,7 +187,7 @@ export default class Init extends BaseCommand { if (this.projectConfig?.codegen?.output) { const { schema: currentSchema } = await ( await this.getXataClient() - ).api.branches.getBranchDetails({ workspace, database, region, branch }); + ).api.branch.getBranchDetails({ pathParams: { workspace, region, dbBranchName: `${database}:${branch}` } }); const hasTables = currentSchema?.tables && currentSchema?.tables.length > 0; const hasColumns = currentSchema?.tables.some((t) => t.columns.length > 0); @@ -434,7 +434,7 @@ export default class Init extends BaseCommand { let retries = 0; while (retries++ < maxRetries) { try { - await xata.api.branches.getBranchList({ workspace, region, database }); + await xata.api.branch.getBranchList({ pathParams: { workspace, region, dbName: database } }); return; } catch (err) { if (err instanceof Error && err.message.includes('Invalid API key')) { diff --git a/cli/src/commands/pull/index.ts b/cli/src/commands/pull/index.ts index 0c51b45b0..f6fe778d6 100644 --- a/cli/src/commands/pull/index.ts +++ b/cli/src/commands/pull/index.ts @@ -51,24 +51,26 @@ export default class Pull extends BaseCommand { const details = await getBranchDetailsWithPgRoll(xata, { workspace, region, database, branch }); - let logs: Schemas.MigrationHistoryItem[] | Schemas.Commit[] = []; + let logs: (Schemas.MigrationHistoryItem | Schemas.Commit)[] = []; + let cursor = undefined; if (isBranchPgRollEnabled(details)) { - const { migrations } = await xata.api.branches.pgRollMigrationHistory({ - workspace, - region, - database, - branch - }); - logs = migrations; + do { + const { migrations, cursor: newCursor } = await xata.api.migrations.getMigrationHistory({ + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + queryParams: { cursor, limit: 200 } + }); + + logs = logs.concat(migrations); + cursor = newCursor; + } while (cursor !== undefined); } else { const data = await xata.api.migrations.getBranchSchemaHistory({ - workspace, - region, - database, - branch, - // TODO: Fix pagination in the API to start from last known migration and not from the beginning - // Also paginate until we get all migrations - page: { size: 200 } + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + body: { + // TODO: Fix pagination in the API to start from last known migration and not from the beginning + // Also paginate until we get all migrations + page: { size: 200 } + } }); logs = data.logs; } diff --git a/cli/src/commands/pull/pull.test.ts b/cli/src/commands/pull/pull.test.ts index 609815eff..290aee7e7 100644 --- a/cli/src/commands/pull/pull.test.ts +++ b/cli/src/commands/pull/pull.test.ts @@ -230,7 +230,7 @@ const pgrollFetchSingle = (url: string, request: any) => { schema: { tables: [{ name: 'table1', columns: [{ name: 'a', type: 'string' }] }] } }) }; - } else if (url === `${baseUrl}/migrations/history` && request.method === 'GET') { + } else if (url === `${baseUrl}/migrations/history?limit=200` && request.method === 'GET') { return { ok: true, json: async () => ({ @@ -251,7 +251,7 @@ const pgrollFetchMultiple = (url: string, request: any) => { schema: { tables: [{ name: 'table1', columns: [{ name: 'a', type: 'string' }] }] } }) }; - } else if (url === `${baseUrl}/migrations/history` && request.method === 'GET') { + } else if (url === `${baseUrl}/migrations/history?limit=200` && request.method === 'GET') { return { ok: true, json: async () => ({ diff --git a/cli/src/commands/push/index.ts b/cli/src/commands/push/index.ts index 4a2d3fb96..343012931 100644 --- a/cli/src/commands/push/index.ts +++ b/cli/src/commands/push/index.ts @@ -1,5 +1,6 @@ import { Args, Flags } from '@oclif/core'; import { Schemas } from '@xata.io/client'; +import { PgRollMigrationDefinition } from '@xata.io/pgroll'; import { BaseCommand } from '../../base.js'; import { LocalMigrationFile, @@ -11,10 +12,10 @@ import { allMigrationsPgRollFormat, getBranchDetailsWithPgRoll, isBranchPgRollEnabled, - isMigrationPgRollFormat + isMigrationPgRollFormat, + waitForMigrationToFinish } from '../../migrations/pgroll.js'; import { MigrationFilePgroll } from '../../migrations/schema.js'; -import { PgRollMigrationDefinition } from '@xata.io/pgroll'; export default class Push extends BaseCommand { static description = 'Push local changes to a remote Xata branch'; @@ -47,24 +48,26 @@ export default class Push extends BaseCommand { const details = await getBranchDetailsWithPgRoll(xata, { workspace, region, database, branch }); - let logs: Schemas.MigrationHistoryItem[] | Schemas.Commit[] = []; + let logs: (Schemas.MigrationHistoryItem | Schemas.Commit)[] = []; + let cursor = undefined; if (isBranchPgRollEnabled(details)) { - const { migrations } = await xata.api.branches.pgRollMigrationHistory({ - workspace, - region, - database, - branch - }); - logs = migrations; + do { + const { migrations, cursor: newCursor } = await xata.api.migrations.getMigrationHistory({ + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + queryParams: { cursor, limit: 200 } + }); + + logs = logs.concat(migrations); + cursor = newCursor; + } while (cursor !== undefined); } else { const data = await xata.api.migrations.getBranchSchemaHistory({ - workspace, - region, - database, - branch, - // TODO: Fix pagination in the API to start from last known migration and not from the beginning - // Also paginate until we get all migrations - page: { size: 200 } + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + body: { + // TODO: Fix pagination in the API to start from last known migration and not from the beginning + // Also paginate until we get all migrations + page: { size: 200 } + } }); logs = data.logs; } @@ -107,14 +110,12 @@ export default class Push extends BaseCommand { .flatMap((migration) => PgRollMigrationDefinition.parse(migration)); for (const migration of migrationsToPush) { try { - await xata.api.branches.applyMigration({ - workspace, - region, - database, - branch, - // @ts-expect-error Backend API spec doesn't know all pgroll migrations yet - migration + const { jobID } = await xata.api.migrations.applyMigration({ + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + body: migration }); + + await waitForMigrationToFinish(xata.api, workspace, region, database, branch, jobID); } catch (e) { this.log(`Failed to push ${migration} with ${e}. Stopping.`); this.exit(1); @@ -123,11 +124,8 @@ export default class Push extends BaseCommand { } else { // TODO: Check for errors and print them await xata.api.migrations.pushBranchMigrations({ - workspace, - region, - database, - branch, - migrations: newMigrations as Schemas.MigrationObject[] + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + body: { migrations: newMigrations as Schemas.MigrationObject[] } }); } diff --git a/cli/src/commands/push/push.test.ts b/cli/src/commands/push/push.test.ts index 94fa78b23..2a8f1f227 100644 --- a/cli/src/commands/push/push.test.ts +++ b/cli/src/commands/push/push.test.ts @@ -188,6 +188,14 @@ const baseFetch = (url: string, request: any) => { } }) }; + } else if ( + url === `https://test-1234.us-east-1.xata.sh/db/db1:main/migrations/jobs/1234` && + request.method === 'GET' + ) { + return { + ok: true, + json: async () => ({ status: 'completed' }) + }; } throw new Error(`Unexpected fetch request: ${url} ${request.method}`); @@ -236,7 +244,7 @@ const pgrollFetchSingle = (url: string, request: any, type: 'inferred' | 'pgroll schema: { tables: [{ name: 'table1', columns: [{ name: 'a', type: 'string' }] }] } }) }; - } else if (url === `${baseUrl}/migrations/history` && request.method === 'GET') { + } else if (url === `${baseUrl}/migrations/history?limit=200` && request.method === 'GET') { return { ok: true, json: async () => (type === 'inferred' ? { migrations: [pgrollMigration3] } : { migrations: [pgrollMigration1] }) @@ -255,7 +263,7 @@ const pgrollFetchEmpty = (url: string, request: any) => { schema: { tables: [{ name: 'table1', columns: [{ name: 'a', type: 'string' }] }] } }) }; - } else if (url === `${baseUrl}/migrations/history` && request.method === 'GET') { + } else if (url === `${baseUrl}/migrations/history?limit=200` && request.method === 'GET') { return { ok: true, json: async () => ({ diff --git a/cli/src/commands/random-data/index.ts b/cli/src/commands/random-data/index.ts index 49c34bbb0..be7e434a1 100644 --- a/cli/src/commands/random-data/index.ts +++ b/cli/src/commands/random-data/index.ts @@ -52,12 +52,8 @@ export default class RandomData extends BaseCommand { const records = generateRandomData(table, totalRecords); await xata.api.records.bulkInsertTableRecords({ - workspace, - region, - database, - branch, - table: table.name, - records + pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table.name }, + body: { records: records as any[] } }); this.info( diff --git a/cli/src/commands/rebase/index.ts b/cli/src/commands/rebase/index.ts index 20d7c9824..f3fafb3ac 100644 --- a/cli/src/commands/rebase/index.ts +++ b/cli/src/commands/rebase/index.ts @@ -7,6 +7,8 @@ import { removeLocalMigrations, writeLocalMigrationFiles } from '../../migrations/files.js'; +import { getBranchDetailsWithPgRoll, isBranchPgRollEnabled } from '../../migrations/pgroll.js'; +import { Schemas } from '@xata.io/client'; export default class Rebase extends BaseCommand { static description = 'Reapply local migrations on top of a remote branch'; @@ -35,29 +37,55 @@ export default class Rebase extends BaseCommand { ); this.info(`Rebase command is experimental, use with caution`); + const details = await getBranchDetailsWithPgRoll(xata, { workspace, region, database, branch }); - const { logs } = await xata.api.migrations.getBranchSchemaHistory({ - workspace, - region, - database, - branch, - // TODO: Fix pagination in the API to start from last known migration and not from the beginning - // Also paginate until we get all migrations - page: { size: 200 } - }); + if (isBranchPgRollEnabled(details)) { + let logs: (Schemas.MigrationHistoryItem | Schemas.Commit)[] = []; + let cursor = undefined; + do { + const { migrations, cursor: newCursor } = await xata.api.migrations.getMigrationHistory({ + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + queryParams: { cursor, limit: 200 } + }); - const remoteMigrationFiles = commitToMigrationFile(logs); - const localMigrationFiles = await getLocalMigrationFiles(); + logs = logs.concat(migrations); + cursor = newCursor; + } while (cursor !== undefined); - const lastCommonMigrationIndex = getLastCommonIndex(localMigrationFiles, remoteMigrationFiles); + const remoteMigrationFiles = commitToMigrationFile(logs); + const localMigrationFiles = await getLocalMigrationFiles(isBranchPgRollEnabled(details)); - const migrationsToRebase = localMigrationFiles.slice(lastCommonMigrationIndex); + const lastCommonMigrationIndex = getLastCommonIndex(localMigrationFiles, remoteMigrationFiles); - const newMigrationFiles = [...remoteMigrationFiles, ...migrationsToRebase]; + const migrationsToRebase = localMigrationFiles.slice(lastCommonMigrationIndex); - // TODO: Check if there are any conflicts + const newMigrationFiles = [...remoteMigrationFiles, ...migrationsToRebase]; - await removeLocalMigrations(); - await writeLocalMigrationFiles(newMigrationFiles); + await removeLocalMigrations(); + await writeLocalMigrationFiles(newMigrationFiles); + } else { + const { logs } = await xata.api.migrations.getBranchSchemaHistory({ + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + body: { + // TODO: Fix pagination in the API to start from last known migration and not from the beginning + // Also paginate until we get all migrations + page: { size: 200 } + } + }); + + const remoteMigrationFiles = commitToMigrationFile(logs); + const localMigrationFiles = await getLocalMigrationFiles(); + + const lastCommonMigrationIndex = getLastCommonIndex(localMigrationFiles, remoteMigrationFiles); + + const migrationsToRebase = localMigrationFiles.slice(lastCommonMigrationIndex); + + const newMigrationFiles = [...remoteMigrationFiles, ...migrationsToRebase]; + + // TODO: Check if there are any conflicts + + await removeLocalMigrations(); + await writeLocalMigrationFiles(newMigrationFiles); + } } } diff --git a/cli/src/commands/schema/edit-old.ts b/cli/src/commands/schema/edit-old.ts new file mode 100644 index 000000000..a5d5784da --- /dev/null +++ b/cli/src/commands/schema/edit-old.ts @@ -0,0 +1,917 @@ +/** + * @deprecated + * This file is deprecated and will be removed when + * all branches have been upgraded to pgroll. + */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { Flags } from '@oclif/core'; +import { Schemas } from '@xata.io/client'; +import { parseSchemaFile } from '@xata.io/codegen'; +import { isValidEmail } from '@xata.io/importer'; +import chalk from 'chalk'; +import enquirer from 'enquirer'; +import { getEditor } from 'env-editor'; +import { readFile, writeFile } from 'fs/promises'; +import tmp from 'tmp'; +import which from 'which'; +import { BaseCommand } from '../../base.js'; +import { getBranchDetailsWithPgRoll } from '../../migrations/pgroll.js'; +import { isNil, reportBugURL } from '../../utils.js'; +import Codegen from '../codegen/index.js'; +import Pull from '../pull/index.js'; + +// The enquirer library has type definitions but they are very poor +const { Select, Snippet, Confirm } = enquirer as any; + +type Schema = Schemas.Schema; +type Table = Schema['tables'][0]; +type Column = Table['columns'][0]; + +type EditableColumn = Column & { + added?: boolean; + deleted?: boolean; + initialName?: string; + description?: string; +}; + +type EditableTable = Table & { + added?: string; + deleted?: boolean; + initialName?: string; + columns: EditableColumn[]; +}; + +type ColumnEditState = { + initial: { + name: string; + type: string; + link: string | undefined; + vectorDimension: string | undefined; + notNull: string; + defaultValue: string; + unique: string; + description: string | undefined; + }; + values: { + name?: string; + type?: string; + link?: string; + vectorDimension?: string; + notNull?: string; + defaultValue?: string; + unique?: string; + description?: string; + }; +}; + +const types = ['string', 'int', 'float', 'bool', 'text', 'multiple', 'link', 'email', 'datetime', 'vector', 'json']; +const typesList = types.join(', '); +const identifier = /^[a-zA-Z0-9-_~]+$/; + +const uniqueUnsupportedTypes = ['text', 'multiple', 'vector', 'json']; +const defaultValueUnsupportedTypes = ['multiple', 'link', 'vector']; +const notNullUnsupportedTypes = defaultValueUnsupportedTypes; + +const waitFlags: Record = { + code: '-w', + 'code-insiders': '-w', + vscodium: '-w', + sublime: '-w', + textmate: '-w', + atom: '--wait', + webstorm: '--wait', + intellij: '--wait', + xcode: '-w' +}; + +type SelectChoice = { + name: + | { + type: 'space' | 'schema' | 'add-table' | 'migrate'; + } + | { + type: 'add-column' | 'edit-table'; + table: EditableTable; + } + | { + type: 'edit-column'; + table: EditableTable; + column: EditableColumn; + }; + message: string; + role?: string; + choices?: SelectChoice[]; + disabled?: boolean; + hint?: string; +}; + +export default class EditSchemaOld extends BaseCommand { + static description = 'Edit the schema of the current database'; + + static examples = []; + + static flags = { + ...this.databaseURLFlag, + branch: this.branchFlag, + source: Flags.boolean({ + description: 'Edit the schema as a JSON document in your default editor' + }) + }; + + static args = {}; + + static hidden = true; + + branchDetails: Schemas.DBBranch | undefined; + tables: EditableTable[] = []; + workspace!: string; + region!: string; + database!: string; + branch!: string; + + selectItem: EditableColumn | EditableTable | null = null; + + async launch({ + workspace, + region, + database, + branch + }: { + workspace: string; + region: string; + database: string; + branch: string; + }) { + this.workspace = workspace; + this.region = region; + this.database = database; + this.branch = branch; + await this.run(); + } + + async run(): Promise { + const { flags } = await this.parseCommand(); + + if (flags.source) { + this.warn( + `This way of editing the schema doesn't detect renames of tables or columns. They are interpreted as deleting/adding tables and columns. +Beware that this can lead to ${chalk.bold( + 'data loss' + )}. Other ways of editing the schema that do not have this limitation are: +* run the command without ${chalk.bold('--source')} +* edit the schema in the Web UI. Use ${chalk.bold('xata browse')} to open the Web UI in your browser.` + ); + this.log(); + } + + const xata = await this.getXataClient(); + + const branchDetails = await getBranchDetailsWithPgRoll(xata, { + workspace: this.workspace, + region: this.region, + database: this.database, + branch: this.branch + }); + if (!branchDetails) this.error('Could not get the schema from the current branch'); + + if (flags.source) { + await this.showSourceEditing(branchDetails); + } else { + await this.showInteractiveEditing(branchDetails); + } + } + + async showSourceEditing(branchDetails: Schemas.DBBranch) { + const env = process.env.EDITOR || process.env.VISUAL; + if (!env) { + this.error( + `Could not find an editor. Please set the environment variable ${chalk.bold('EDITOR')} or ${chalk.bold( + 'VISUAL' + )}` + ); + } + + const info = await getEditor(env); + // This honors the env value. For `code-insiders` for example, we don't want `code` to be used instead. + const binary = which.sync(env, { nothrow: true }) ? env : info.binary; + + const tmpobj = tmp.fileSync({ prefix: 'schema-', postfix: 'source.json' }); + // TODO: add a $schema to the document to allow autocomplete in editors such as vscode + await writeFile(tmpobj.name, JSON.stringify(branchDetails.schema, null, 2)); + + const waitFlag = waitFlags[info.id] || waitFlags[env]; + + if (!info.isTerminalEditor && !waitFlag) { + this.error(`The editor ${chalk.bold(env)} is a graphical editor that is not supported.`, { + suggestions: [ + `Set the ${chalk.bold('EDITOR')} or ${chalk.bold('VISUAL')} variables to a different editor`, + `Open an issue at ${reportBugURL(`Support \`${info.binary}\` editor for schema editing`)}` + ] + }); + } + + const args = [waitFlag, tmpobj.name].filter(Boolean); + await this.runCommand(binary, args); + + const newSchema = await readFile(tmpobj.name, 'utf8'); + const result = parseSchemaFile(newSchema); + if (!result.success) { + this.printZodError(result.error); + this.error('The schema is not valid. See the errors above'); + } + + await this.deploySchema(this.workspace, this.region, this.database, this.branch, result.data); + + // Run pull to retrieve remote migrations + await Pull.run([this.branch]); + } + + async showInteractiveEditing(branchDetails: Schemas.DBBranch) { + this.branchDetails = branchDetails; + this.tables = this.branchDetails.schema.tables; + await this.showSchema(); + } + + async showSchema() { + this.clear(); + + const choices: SelectChoice[] = [ + this.createSpace() // empty space + ]; + const flatChoices = [...choices]; + + const tableChoices: SelectChoice[] = []; + const schema: SelectChoice = { + name: { type: 'schema' }, + message: 'Tables', + role: 'heading', + choices: tableChoices + }; + choices.push(schema); + flatChoices.push(schema); + + let index = 0; + for (const table of this.tables) { + const columnChoices: SelectChoice[] = table.columns.map((column, i) => { + if (this.selectItem === column) index = flatChoices.length + i + 1; + return { + name: { type: 'edit-column', column, table }, + message: this.getMessageForColumn(table, column) + }; + }); + columnChoices.push({ + message: `${chalk.green('+')} Add a column`, + name: { type: 'add-column', table }, + disabled: table.deleted + }); + const tableChoice: SelectChoice = { + name: { type: 'edit-table', table }, + message: this.getMessageForTable(table), + choices: columnChoices + }; + tableChoices.push(tableChoice); + if (this.selectItem === table) index = flatChoices.length; + flatChoices.push(tableChoice); + flatChoices.push(...columnChoices); + tableChoices.push(this.createSpace()); + flatChoices.push(this.createSpace()); + } + + choices.push({ message: `${chalk.green('+')} Add a table`, name: { type: 'add-table' } }); + choices.push(this.createSpace()); + + const overview = this.getOverview(); + choices.push({ + message: `${chalk.green('►')} Run migration${overview ? ':' : ''}`, + name: { type: 'migrate' }, + disabled: !overview, + hint: overview || 'No changes made so far' + }); + choices.push(this.createSpace()); + + const select = new Select({ + message: 'Schema for database test:main', + initial: index, + choices, + footer: + 'Use the ↑ ↓ arrows to move across the schema, enter to edit or add things, delete or backspace to delete things.' + }); + select.on('keypress', async (char: string, key: { name: string; action: string }) => { + const flatChoice = flatChoices[select.state.index]; + try { + if (key.name === 'backspace' || key.name === 'delete') { + if (!flatChoice) return; // add table is not here for example + const choice = flatChoice.name; + if (typeof choice !== 'object') return; + + if (choice.type === 'edit-table') { + await select.cancel(); + await this.deleteTable(choice.table); + } else if (choice.type === 'edit-column' && !choice.table.deleted) { + await select.cancel(); + await this.deleteColumn(choice.column, choice.table); + } + } + } catch (err) { + if (err) throw err; + this.clear(); + } + }); + + try { + const result = await select.run(); + + if (result.type === 'edit-column') { + await this.showColumnEdit(result.column, result.table); + } else if (result.type === 'edit-table') { + await this.showTableEdit(result.table); + } else if (result.type === 'add-column') { + await this.showColumnEdit(null, result.table); + } else if (result.type === 'add-table') { + await this.showTableEdit(null); + } else if (result.type === 'delete-table') { + await this.deleteTable(result.table); + } else if (result.type === 'migrate') { + await this.migrate(); + await Codegen.runIfConfigured(this.projectConfig); + process.exit(0); + } + } catch (err) { + if (err) throw err; + // if not, user cancelled + } + + this.clear(); + } + + createSpace(): SelectChoice { + return { name: { type: 'space' }, message: ' ', role: 'heading' }; + } + + getMessageForTable(table: EditableTable) { + if (table.deleted) return `• ${chalk.red.strikethrough(table.name)}`; + if (table.added) return `• ${chalk.green(table.name)}`; + if (table.initialName) return `• ${chalk.bold(table.name)} ${chalk.yellow.strikethrough(table.initialName)}`; + return `• ${chalk.bold(table.name)}`; + } + + getMessageForColumn(table: EditableTable, column: EditableColumn) { + const linkedTable = this.tables.find((t) => (t.initialName || t.name) === column.link?.table); + function getType() { + if (!linkedTable) return chalk.gray.italic(column.type); + return `${chalk.gray.italic(column.type)} → ${chalk.gray.italic(linkedTable.name)}`; + } + const metadata = [ + getType(), + column.unique ? chalk.gray.italic('unique') : '', + column.notNull ? chalk.gray.italic('not null') : '', + column.defaultValue ? chalk.gray.italic(`default: ${column.defaultValue}`) : '' + ] + .filter(Boolean) + .join(' '); + if (table.deleted || column.deleted || linkedTable?.deleted) + return `- ${chalk.red.strikethrough(column.name)} (${metadata})`; + if (table.added || column.added) return `- ${chalk.green(column.name)} (${metadata})`; + if (column.initialName) + return `- ${chalk.cyan(column.name)} ${chalk.yellow.strikethrough(column.initialName)} (${metadata})`; + return `- ${chalk.cyan(column.name)} (${metadata})`; + } + + getOverview() { + const info = { + tables: { added: 0, deleted: 0, modified: 0 }, + columns: { added: 0, deleted: 0, modified: 0 } + }; + for (const table of this.tables) { + if (table.added) info.tables.added++; + else if (table.deleted) info.tables.deleted++; + else if (table.initialName) info.tables.modified++; + + for (const column of table.columns) { + const linkedTable = this.tables.find((t) => (t.initialName || t.name) === column.link?.table); + if (table.added || column.added) info.columns.added++; + else if (table.deleted || column.deleted || linkedTable?.deleted) info.columns.deleted++; + else if (column.initialName) info.columns.modified++; + } + } + + const tablesOverview = [ + info.tables.added ? `${chalk.green(`+${info.tables.added}`)}` : null, + info.tables.deleted ? `${chalk.red(`-${info.tables.deleted}`)}` : null, + info.tables.modified ? `${chalk.yellow(`·${info.tables.modified}`)}` : null + ].filter(Boolean); + + const columnsOverview = [ + info.columns.added ? `${chalk.green(`+${info.columns.added}`)}` : null, + info.columns.deleted ? `${chalk.red(`-${info.columns.deleted}`)}` : null, + info.columns.modified ? `${chalk.yellow(`·${info.columns.modified}`)}` : null + ].filter(Boolean); + + const messages = [ + tablesOverview.length > 0 ? `${tablesOverview.join(', ')} tables` : null, + columnsOverview.length > 0 ? `${columnsOverview.join(', ')} columns` : null + ].filter(Boolean); + + return messages.join(', '); + } + + async showColumnEdit(column: EditableColumn | null, table: EditableTable) { + this.clear(); + const isColumnAdded = !column || column?.added; + const template = ` + name: \${name} + type: \${type} + link: \${link} +vectorDimension: \${vectorDimension} + description: \${description} + unique: \${unique} + notNull: \${notNull} + defaultValue: \${defaultValue}`; + + const initial: ColumnEditState['initial'] = { + name: column?.name || '', + type: column?.type || '', + link: isColumnAdded ? '' : column?.link?.table, + vectorDimension: column?.vector?.dimension ? `${column?.vector?.dimension}` : undefined, + notNull: column?.notNull ? 'true' : 'false', + defaultValue: column?.defaultValue || '', + unique: column?.unique ? 'true' : 'false', + description: isColumnAdded ? '' : column?.description + }; + const snippet: any = new Snippet({ + message: column?.name || 'a new column', + initial, + fields: [ + { + name: 'name', + message: 'The column name', + validate(value: string | undefined, state: ColumnEditState, item: unknown, index: number) { + if (!identifier.test(value || '')) { + return snippet.styles.danger(`Column name has to match ${identifier}`); + } + return true; + } + }, + { + name: 'type', + message: `The column type (${typesList})`, + validate(value: string | undefined, state: ColumnEditState, item: unknown, index: number) { + if (!isColumnAdded && value !== state.initial.type) { + return `Cannot change the type of existing columns`; + } + if (!value || !types.includes(value)) { + return `Type needs to be one of ${typesList}`; + } + return true; + } + }, + { + name: 'link', + message: 'Linked table. Only for columns that are links', + validate( + value: string | undefined, + state: ColumnEditState, + item: { value: string | undefined }, + index: number + ) { + if (!isColumnAdded && value !== state.initial.link) { + return `Cannot change the link of existing link columns`; + } + if (state.values.type === 'link') { + if (!value) { + return 'The link field must be filled for columns of type `link`'; + } + } else if (value) { + return 'The link field must not be filled unless the type of the column is `link`'; + } + return true; + } + }, + { + name: 'vectorDimension', + message: 'Vector Dimension. Only for columns that are vectors', + validate( + value: string | undefined, + state: ColumnEditState, + item: { value: string | undefined }, + index: number + ) { + if (!isColumnAdded && value !== state.initial.vectorDimension) { + return `Cannot change the vector dimension of existing vector columns`; + } + if (state.values.type === 'vector') { + if (!value) { + return 'The vectorDimension field must be filled for columns of type `vector`'; + } + } else if (value) { + return 'The vectorDimension field must not be filled unless the type of the column is `vector`'; + } + return true; + } + }, + { + name: 'unique', + message: 'Whether the column is unique (true/false)', + validate(value: string | undefined, state: ColumnEditState, item: unknown, index: number) { + if (!isColumnAdded && parseBoolean(value) !== parseBoolean(state.initial.unique)) { + return `Cannot change unique for existing columns`; + } + const validateOptionalBooleanResult = validateOptionalBoolean(value); + if (validateOptionalBooleanResult !== true) { + return validateOptionalBooleanResult; + } + const validateUniqueResult = validateUnique(value, state); + if (validateUniqueResult !== true) { + return validateUniqueResult; + } + return true; + } + }, + { + name: 'notNull', + message: 'Whether the column is not nullable (true/false)', + validate(value: string | undefined, state: ColumnEditState, item: unknown, index: number) { + if (!isColumnAdded && parseBoolean(value) !== parseBoolean(state.initial.notNull)) { + return `Cannot change notNull for existing columns`; + } + const validateOptionalBooleanResult = validateOptionalBoolean(value); + if (validateOptionalBooleanResult !== true) { + return validateOptionalBooleanResult; + } + const validateNotNullResult = validateNotNull(value, state); + if (validateNotNullResult !== true) { + return validateNotNullResult; + } + return true; + } + }, + { + name: 'description', + message: 'An optional column description', + validate(value: string | undefined, state: ColumnEditState, item: unknown, index: number) { + if (!isColumnAdded && value !== state.initial.description) { + return `Cannot change description for existing columns`; + } + return true; + } + }, + { + name: 'defaultValue', + message: 'Default value', + validate(rawDefaultValue: string | undefined, state: ColumnEditState, item: unknown, index: number) { + if ( + !isColumnAdded && + state.values.type && + parseDefaultValue(state.values.type, rawDefaultValue) !== + parseDefaultValue(state.values.type, state.initial.defaultValue) + ) { + return `Cannot change defaultValue for existing columns`; + } + if (state.values.type) { + const isNotNull = parseBoolean(state.values.notNull) === true; + const defaultValue = parseDefaultValue(state.values.type, rawDefaultValue); + if (isNotNull && (!rawDefaultValue || rawDefaultValue.length === 0)) { + return 'defaultValue must be set for `notNull: true` columns'; + } + if (rawDefaultValue && rawDefaultValue.length > 0 && defaultValue === undefined) { + return `Invalid defaultValue for Type: ${state.values.type}`; + } + } + return true; + } + } + ], + footer() { + return '\nUse the ↑ ↓ arrows to move across fields, enter to submit and escape to cancel.'; + }, + template + }); + + try { + const { values } = await snippet.run(); + const unique = parseBoolean(values.unique); + const notNull = parseBoolean(values.notNull); + const col: Column = { + name: values.name, + type: values.type, + link: values.link && values.type === 'link' ? { table: values.link } : undefined, + vector: values.vectorDimension ? { dimension: parseInt(values.vectorDimension, 10) } : undefined, + unique: unique || undefined, + notNull: notNull || undefined, + defaultValue: parseDefaultValue(values.type, values.defaultValue) + // TODO: add description once the backend supports it + // description: values.description + }; + if (column) { + if (!column.initialName && !column.added && column.name !== values.name) { + column.initialName = column.name; + } + Object.assign(column, col); + if (column.name === column.initialName) { + delete column.initialName; + } + } else { + table.columns.push({ + ...col, + added: true + }); + // Override the variable to use it when redefining this.selectItem below + column = table.columns[table.columns.length - 1]; + } + } catch (err) { + if (err) throw err; + // if not, user cancelled + } + + this.selectItem = column; + await this.showSchema(); + } + + async showTableEdit(table: EditableTable | null) { + this.clear(); + + const snippet = new Snippet({ + message: table ? table.name : 'a new table', + initial: { + name: table ? table.name : '' + }, + fields: [ + { + name: 'name', + message: 'The table name', + validate(value: string, state: unknown, item: unknown, index: number) { + if (!identifier.test(value || '')) { + return snippet.styles.danger(`Table name has to match ${identifier}`); + } + return true; + } + }, + { + name: 'description', + message: 'An optional table description' + } + ], + footer() { + return '\nUse the ↑ ↓ arrows to move across fields, enter to submit and escape to cancel.'; + }, + template: ` + Name: \${name} + Description: \${description}` + }); + + try { + const answer = await snippet.run(); + if (table) { + if (!table.initialName && !table.added && table.name !== answer.values.name) { + table.initialName = table.name; + } + Object.assign(table, answer.values); + if (table.name === table.initialName) { + delete table.initialName; + } + } else { + this.tables.push({ + ...answer.values, + columns: [], + added: true + }); + // Override the variable to use it when redefining this.selectItem below + table = this.tables[this.tables.length - 1]; + } + } catch (err) { + if (err) throw err; + // if not, user cancelled + } + + this.selectItem = table; + await this.showSchema(); + } + + async deleteTable(table: EditableTable) { + if (table.added) { + const index = this.tables.indexOf(table); + this.tables.splice(index, 1); + // TODO: select other table? + } else { + table.deleted = !table.deleted; + this.selectItem = table; + } + + this.clear(); + await this.showSchema(); + } + + async deleteColumn(column: EditableColumn, table: EditableTable) { + if (column.added) { + const index = table.columns.indexOf(column); + table.columns.splice(index, 1); + // TODO: select other column? + this.selectItem = table; + } else { + column.deleted = !column.deleted; + this.selectItem = column; + } + + this.clear(); + await this.showSchema(); + } + + clear() { + process.stdout.write('\x1b[2J'); + process.stdout.write('\x1b[0f'); + } + + async migrate() { + this.clear(); + + if (!this.branchDetails) this.error('Branch details are not available'); + + const prompt = new Confirm({ + name: 'question', + message: `Are you sure you want to run the migration? ${this.getOverview()}` + }); + + try { + const answer = await prompt.run(); + if (!answer) { + await this.showSchema(); + return; + } + } catch (err) { + if (err) throw err; + // User cancelled + await this.showSchema(); + return; + } + + const workspace = this.workspace; + const region = this.region; + const database = this.database; + + const xata = await this.getXataClient(); + const branch = this.branchDetails.branchName; + + const edits: Schemas.SchemaEditScript = { + operations: [] + }; + + // Create tables, update tables, delete columns and update columns + for (const table of this.tables) { + if (table.added) { + this.info(`Creating table ${table.name}`); + edits.operations.push({ + addTable: { + table: table.name + } + }); + // await xata.tables.createTable({ workspace, region, database, branch, table: table.name }); + } else if (table.initialName) { + this.info(`Renaming table ${table.initialName} to ${table.name}`); + edits.operations.push({ + renameTable: { + newName: table.name, + oldName: table.initialName + } + }); + } + + for (const column of table.columns) { + const linkedTable = this.tables.find((t) => (t.initialName || t.name) === column.link?.table); + if (column.deleted || linkedTable?.deleted) { + this.info(`Deleting column ${table.name}.${column.name}`); + edits.operations.push({ + removeColumn: { + table: table.name, + column: column.name + } + }); + } else if (column.initialName) { + this.info(`Renaming column ${table.name}.${column.initialName} to ${table.name}.${column.name}`); + edits.operations.push({ + renameColumn: { + table: table.name, + newName: column.name, + oldName: column.initialName + } + }); + } + } + } + + // Delete tables and create columns + for (const table of this.tables) { + if (table.deleted) { + this.info(`Deleting table ${table.name}`); + edits.operations.push({ + removeTable: { + table: table.name + } + }); + continue; + } + + for (const column of table.columns) { + if (table.added || column.added) { + this.info(`Adding column ${table.name}.${column.name}`); + edits.operations.push({ + addColumn: { + table: table.name, + column: { + name: column.name, + type: column.type, + link: column.link, + vector: column.vector, + unique: column.unique, + notNull: column.notNull, + defaultValue: column.defaultValue + } + } + }); + } + } + } + + await xata.api.migrations.applyBranchSchemaEdit({ + pathParams: { + workspace, + region, + dbBranchName: `${database}:${branch}` + }, + body: { + edits + } + }); + + this.success('Migration completed!'); + } +} + +function parseBoolean(value?: string) { + if (!value) return undefined; + const val = value.toLowerCase(); + if (['true', 't', '1', 'y', 'yes'].includes(val)) return true; + if (['false', 'f', '0', 'n', 'no'].includes(val)) return false; + return null; +} + +function validateOptionalBoolean(value?: string) { + const bool = parseBoolean(value); + if (bool === null) { + return 'Please enter a boolean value (e.g. yes, no, true, false) or leave it empty'; + } + return true; +} + +function validateUnique(uniqueValue: string | undefined, state: ColumnEditState) { + const isUnique = parseBoolean(uniqueValue); + if (isUnique && state.values.type && uniqueUnsupportedTypes.includes(state.values.type)) { + return `Column type \`${state.values.type}\` does not support \`unique: true\``; + } + if (isUnique && parseBoolean(state.values.notNull)) { + return 'Column cannot be both `unique: true` and `notNull: true`'; + } + if (isUnique && state.values.defaultValue) { + return 'Column cannot be both `unique: true` and have a `defaultValue` set'; + } + return true; +} + +function validateNotNull(notNullValue: string | undefined, state: ColumnEditState) { + const isNotNull = parseBoolean(notNullValue); + if (isNotNull && state.values.type && notNullUnsupportedTypes.includes(state.values.type)) { + return `Column type \`${state.values.type}\` does not support \`notNull: true\``; + } + + return true; +} + +function parseDefaultValue(type: string, val?: string): string | undefined { + if (val === undefined || defaultValueUnsupportedTypes.includes(type)) { + return undefined; + } + const num = String(val).length > 0 ? +val : undefined; + + if (['text', 'string'].includes(type)) { + return val === '' ? undefined : String(val); + } else if (type === 'int') { + return Number.isSafeInteger(num) && val !== '' ? String(num) : undefined; + } else if (type === 'float') { + return Number.isFinite(num) && val !== '' ? String(num) : undefined; + } else if (type === 'bool') { + const booleanValue = parseBoolean(val); + return !isNil(booleanValue) ? String(booleanValue) : undefined; + } else if (type === 'email') { + if (!isValidEmail(val)) { + return undefined; + } + return val; + } else if (type === 'datetime') { + // Date fields have special values + if (['now'].includes(val)) return val; + + const date = new Date(val); + return isNaN(date.getTime()) ? undefined : date.toISOString(); + } else { + return undefined; + } +} diff --git a/cli/src/commands/schema/edit.test.ts b/cli/src/commands/schema/edit.test.ts new file mode 100644 index 000000000..d13ac6953 --- /dev/null +++ b/cli/src/commands/schema/edit.test.ts @@ -0,0 +1,895 @@ +import { beforeEach, expect, test, describe } from 'vitest'; +import { + AddColumnPayload, + AddTablePayload, + ColumnAdditions, + ColumnData, + ColumnEdits, + DeleteColumnPayload, + DeleteTablePayload, + EditTablePayload +} from './edit'; +import { PgRollMigration } from '@xata.io/pgroll'; +import EditSchemaNew, { editsToMigrations } from './edit'; + +const column: AddColumnPayload['column'] = { + name: 'col1', + type: 'string', + unique: false, + nullable: true, + originalName: 'col1', + tableName: 'table1' +}; + +class mockEdit { + tableAdditions: AddTablePayload['table'][] = []; + tableEdits: EditTablePayload['table'][] = []; + tableDeletions: DeleteTablePayload[] = []; + columnAdditions: ColumnAdditions = {}; + columnEdits: ColumnEdits = {}; + columnDeletions: DeleteColumnPayload = {}; + currentMigration: PgRollMigration = { operations: [] }; + + branchDetails: any = { + databaseName: 'abc', + branchName: 'main', + createdAt: '2024-04-11T09:23:20.517Z', + id: 'bb_i4b697b2ul4fd29vk5snu5q8ss_guvr8p', + clusterID: 'shared-cluster', + lastMigrationID: '', + version: 1, + schema: { + tables: [ + { + name: 'table1', + checkConstraints: {}, + foreignKeys: {}, + primaryKey: [], + uniqueConstraints: {}, + columns: [column] + }, + { + name: 'table2', + foreignKeys: {}, + primaryKey: [], + uniqueConstraints: { + ['table2_col1_unique']: { + name: 'table2_col1_unique', + columns: ['col1'] + } + }, + checkConstraints: { + ['table2_xata_string_length_col1']: { + name: 'table2_xata_string_length_col1', + constraint: 'LENGTH("col1") <= 2048' + } + }, + columns: [ + { + ...column, + unique: true, + type: 'varchar(255)' + } + ] + } + ] + }, + metadata: {}, + usePgRoll: true + }; +} + +const editCommand = new mockEdit(); + +beforeEach(() => { + editCommand.tableAdditions = []; + editCommand.tableEdits = []; + editCommand.tableDeletions = []; + editCommand.columnAdditions = {}; + editCommand.columnEdits = {}; + editCommand.columnDeletions = {}; + editCommand.currentMigration = { operations: [] }; +}); + +const createAddition = (column: ColumnData) => { + if (!editCommand.columnAdditions[column.tableName]) editCommand.columnAdditions[column.tableName] = {}; + if (!editCommand.columnAdditions[column.tableName][column.originalName]) + editCommand.columnAdditions[column.tableName][column.originalName] = {} as any; + editCommand.columnAdditions[column.tableName][column.originalName] = column; +}; + +const createEdit = (column: ColumnData) => { + if (!editCommand.columnEdits[column.tableName]) editCommand.columnEdits[column.tableName] = {}; + if (!editCommand.columnEdits[column.tableName][column.originalName]) + editCommand.columnEdits[column.tableName][column.originalName] = {} as any; + editCommand.columnEdits[column.tableName][column.originalName] = column; +}; + +const runTest = (name: string, setup: () => void, expectation: any) => { + test(name, () => { + setup(); + editCommand.currentMigration.operations = editsToMigrations(editCommand as EditSchemaNew); + expect(editCommand.currentMigration.operations).toEqual(expectation); + }); +}; + +type TestCase = { + name: string; + setup: () => void; + expectation: any; + only?: boolean; +}; + +const testCases: TestCase[] = [ + { + name: 'add table', + setup: () => { + editCommand.tableAdditions.push({ name: 'table1' }); + }, + expectation: [{ create_table: { name: 'table1', columns: [] } }] + }, + { + name: 'delete table', + setup: () => { + editCommand.tableDeletions.push({ name: 'table1' }); + }, + expectation: [{ drop_table: { name: 'table1' } }] + }, + { + name: 'edit table', + setup: () => { + editCommand.tableEdits.push({ name: 'table1', newName: 'table2' }); + }, + expectation: [{ rename_table: { from: 'table1', to: 'table2' } }] + }, + { + name: 'add column', + setup: () => { + createAddition(column); + }, + expectation: [ + { + add_column: { + table: 'table1', + column: { + name: 'col1', + type: 'text', + nullable: true, + unique: false, + check: { + constraint: 'LENGTH("col1") <= 2048', + name: 'table1_xata_string_length_col1' + }, + up: undefined, + comment: '{"xata.type":"string"}', + default: undefined, + references: undefined + } + } + } + ] + }, + { + name: 'add column default', + setup: () => { + createAddition({ + ...column, + type: 'int', + defaultValue: '10000' + }); + }, + expectation: [ + { + add_column: { + table: 'table1', + column: { + name: 'col1', + type: 'bigint', + references: undefined, + default: "'10000'", + nullable: true, + unique: false + } + } + } + ] + }, + { + name: 'add column not null', + setup: () => { + createAddition({ + ...column, + type: 'int', + nullable: false + }); + }, + expectation: [ + { + add_column: { + table: 'table1', + column: { + name: 'col1', + type: 'bigint', + references: undefined, + nullable: false, + unique: false + }, + up: '0' + } + } + ] + }, + { + name: 'add column unique', + setup: () => { + createAddition({ + ...column, + type: 'int', + unique: true + }); + }, + expectation: [ + { + add_column: { + table: 'table1', + column: { + name: 'col1', + type: 'bigint', + references: undefined, + up: undefined, + nullable: true, + unique: true + } + } + } + ] + }, + { + name: 'add column file', + setup: () => { + createAddition({ + ...column, + type: 'file', + file: { + defaultPublicAccess: false + } + }); + }, + expectation: [ + { + add_column: { + table: 'table1', + column: { + name: 'col1', + comment: '{"xata.file.dpa":false}', + type: 'xata.xata_file', + references: undefined, + up: undefined, + nullable: true, + unique: false + } + } + } + ] + }, + { + name: 'add column file[]', + setup: () => { + createAddition({ + ...column, + type: 'file[]', + 'file[]': { + defaultPublicAccess: true + } + }); + }, + expectation: [ + { + add_column: { + table: 'table1', + column: { + name: 'col1', + comment: '{"xata.file.dpa":true}', + type: 'xata.xata_file_array', + references: undefined, + up: undefined, + nullable: true, + unique: false + } + } + } + ] + }, + { + name: 'add column vector', + setup: () => { + createAddition({ + ...column, + type: 'vector', + vector: { + dimension: 10 + } + }); + }, + expectation: [ + { + add_column: { + table: 'table1', + column: { + name: 'col1', + check: { + constraint: 'ARRAY_LENGTH("col1", 1) = 10', + name: 'table1_xata_vector_length_col1' + }, + type: 'real[]', + nullable: true, + unique: false, + comment: '{"xata.search.dimension":10}', + references: undefined, + up: undefined, + default: undefined + } + } + } + ] + }, + { + name: 'add link column', + setup: () => { + createAddition({ + ...column, + type: 'link', + link: { table: 'table2' } + }); + }, + expectation: [ + { + add_column: { + table: 'table1', + column: { + name: 'col1', + type: 'text', + nullable: true, + unique: false, + comment: '{"xata.link":"table2"}', + references: { + column: 'xata_id', + name: 'col1_link', + on_delete: 'SET NULL', + table: 'table2' + }, + default: undefined, + up: undefined + } + } + } + ] + }, + { + name: 'edit column', + setup: () => { + createEdit({ + ...column, + name: 'col2' + }); + }, + expectation: [ + { + alter_column: { + name: 'col2', + column: 'col1', + table: 'table1' + } + } + ] + }, + // TODO update link comment test + { + name: 'edit column nullable to not nullable', + setup: () => { + createEdit({ + ...column, + nullable: false + }); + }, + expectation: [ + { + alter_column: { + column: 'col1', + nullable: false, + table: 'table1', + up: '(SELECT CASE WHEN "col1" IS NULL THEN \'\' ELSE "col1" END)', + down: '(SELECT CASE WHEN "col1" IS NULL THEN \'\' ELSE "col1" END)' + } + } + ] + }, + { + name: 'edit column not unique to unique', + setup: () => { + createEdit({ + ...column, + unique: true + }); + }, + expectation: [ + { + alter_column: { + column: 'col1', + down: '"col1"', + up: '"col1"', + table: 'table1', + unique: { + name: 'table1_col1_unique' + } + } + } + ] + }, + { + name: 'edit column unique to not unique also drops the constraint', + setup: () => { + createEdit({ + ...column, + tableName: 'table2', + unique: false + }); + }, + expectation: [ + { + drop_constraint: { + table: 'table2', + down: '"col1"', + up: '"col1"', + column: 'col1', + name: 'table2_col1_unique' + } + } + ] + }, + { + name: 'deleting an existing table deletes all table edits', + setup: () => { + editCommand.tableEdits.push({ name: 'table1', newName: 'table2' }); + editCommand.tableDeletions.push({ name: 'table1' }); + }, + expectation: [{ drop_table: { name: 'table1' } }] + }, + { + name: 'deleting an existing table deletes all column edits', + setup: () => { + createEdit({ + ...column, + name: 'col2' + }); + editCommand.tableDeletions.push({ name: 'table1' }); + }, + expectation: [{ drop_table: { name: 'table1' } }] + }, + { + name: 'deleting an existing table deletes all column deletes', + setup: () => { + editCommand.columnDeletions['table1'] = ['col1']; + editCommand.tableDeletions.push({ name: 'table1' }); + }, + expectation: [{ drop_table: { name: 'table1' } }] + }, + { + name: 'deleting an existing table deletes all column additions', + setup: () => { + createAddition(column); + editCommand.tableDeletions.push({ name: 'table1' }); + }, + expectation: [{ drop_table: { name: 'table1' } }] + }, + { + name: 'creating a new column and deleting an existing table', + setup: () => { + createAddition(column); + editCommand.columnDeletions['table1'] = ['col1']; + createAddition({ + ...column, + originalName: 'col2', + name: 'col2' + }); + }, + expectation: [ + { + add_column: { + table: 'table1', + column: { + name: 'col2', + type: 'text', + nullable: true, + unique: false, + check: { + constraint: 'LENGTH("col2") <= 2048', + name: 'table1_xata_string_length_col2' + }, + comment: '{"xata.type":"string"}', + default: undefined, + references: undefined, + up: undefined + } + } + } + ] + }, + { + name: 'deleting an existing column deletes all column edits', + setup: () => { + createEdit({ + ...column, + name: 'col2' + }); + editCommand.columnDeletions['table1'] = ['col1']; + }, + expectation: [ + { + drop_column: { + column: 'col1', + table: 'table1' + } + } + ] + }, + + { + name: 'deleting a new table deletes all table edits', + setup: () => { + editCommand.tableAdditions.push({ name: 'table1' }); + editCommand.tableEdits.push({ name: 'table1', newName: 'table2' }); + editCommand.tableDeletions.push({ name: 'table1' }); + }, + expectation: [] + }, + { + name: 'deleting a new table deletes all column edits', + setup: () => { + editCommand.tableAdditions.push({ name: 'table1' }); + createEdit({ + ...column, + name: 'col2' + }); + editCommand.tableDeletions.push({ name: 'table1' }); + }, + expectation: [] + }, + + { + name: 'deleting a new table deletes all column deletes', + setup: () => { + editCommand.tableAdditions.push({ name: 'table1' }); + editCommand.columnDeletions['table1'] = ['col1']; + editCommand.tableDeletions.push({ name: 'table1' }); + }, + expectation: [] + }, + + { + name: 'deleting a new table deletes all column additions', + setup: () => { + editCommand.tableAdditions.push({ name: 'table1' }); + createAddition(column); + editCommand.tableDeletions.push({ name: 'table1' }); + }, + expectation: [] + }, + { + name: 'editing a new table is bundled with the table addition', + setup: () => { + editCommand.tableAdditions.push({ name: 'table1' }); + editCommand.tableEdits.push({ name: 'table1', newName: 'table2' }); + }, + expectation: [ + { + create_table: { name: 'table2', columns: [] } + } + ] + }, + { + name: 'editing a new table removes the table edit', + setup: () => { + editCommand.tableAdditions.push({ name: 'table1' }); + editCommand.tableEdits.push({ name: 'table1', newName: 'table2' }); + }, + expectation: [ + { + create_table: { name: 'table2', columns: [] } + } + ] + }, + { + name: 'adding a column on a new table with unique = false is sent correctly', + setup: () => { + editCommand.tableAdditions.push({ name: 'table1' }); + createAddition({ + ...column, + type: 'float', + unique: true + }); + }, + expectation: [ + { + create_table: { + name: 'table1', + columns: [ + { + name: 'col1', + type: 'double precision', + nullable: true, + unique: true, + default: undefined, + references: undefined, + up: undefined + } + ] + } + } + ] + }, + { + name: 'adding a column on a new table with nullable = false is sent correctly', + setup: () => { + editCommand.tableAdditions.push({ name: 'table1' }); + createAddition({ + ...column, + type: 'float', + nullable: false + }); + }, + expectation: [ + { + create_table: { + name: 'table1', + columns: [ + { + name: 'col1', + type: 'double precision', + nullable: false, + unique: false, + default: undefined, + references: undefined + } + ] + } + } + ] + }, + { + name: 'adding a column on a new table with nullable = false is sent correctly', + setup: () => { + editCommand.tableAdditions.push({ name: 'table1' }); + createAddition({ + ...column, + type: 'float', + nullable: false + }); + }, + expectation: [ + { + create_table: { + name: 'table1', + columns: [ + { + name: 'col1', + type: 'double precision', + nullable: false, + unique: false, + default: undefined, + references: undefined + } + ] + } + } + ] + }, + { + name: 'adding a column on a new table with nullable = true is sent correctly', + setup: () => { + editCommand.tableAdditions.push({ name: 'table1' }); + createAddition({ + ...column, + type: 'float', + nullable: true + }); + }, + expectation: [ + { + create_table: { + name: 'table1', + columns: [ + { + name: 'col1', + type: 'double precision', + nullable: true, + unique: false, + default: undefined, + references: undefined, + up: undefined + } + ] + } + } + ] + }, + { + name: 'deleting a new column deletes all column additions, edit and deletions', + setup: () => { + createAddition(column); + createEdit({ + ...column, + name: 'col2' + }); + editCommand.columnDeletions['table1'] = ['col1']; + }, + expectation: [] + }, + { + name: 'deleting a newly created column does not remove other deletes', + setup: () => { + editCommand.columnDeletions['table1'] = ['col1']; + createAddition({ + ...column, + originalName: 'col2', + name: 'col3', + type: 'float' + }); + editCommand.columnDeletions['table1'].push('col2'); + }, + expectation: [ + { + drop_column: { + column: 'col1', + table: 'table1' + } + } + ] + }, + { + name: 'adding a newly created column and making edit', + setup: () => { + createAddition({ + ...column, + type: 'float' + }); + createEdit({ + ...column, + type: 'float', + name: 'col5', + nullable: false, + unique: true + }); + createEdit({ + ...column, + type: 'float', + name: 'col6', + nullable: false, + unique: true + }); + }, + expectation: [ + { + add_column: { + table: 'table1', + column: { + name: 'col6', + type: 'double precision', + nullable: false, + unique: true, + default: undefined, + references: undefined + }, + up: '0' + } + } + ] + }, + { + name: 'editing a new column in an existing table removes the column edit, and gets sent in add_column', + setup: () => { + createAddition(column); + createEdit({ + ...column, + name: 'col2' + }); + }, + expectation: [ + { + add_column: { + table: 'table1', + column: { + name: 'col2', + type: 'text', + nullable: true, + unique: false, + check: { + constraint: 'LENGTH("col2") <= 2048', + name: 'table1_xata_string_length_col2' + }, + comment: '{"xata.type":"string"}', + default: undefined, + references: undefined, + up: undefined + } + } + } + ] + }, + { + name: 'deleting a new column deletes all column additions, edits, and deletions', + setup: () => { + createAddition(column); + createEdit({ + ...column, + name: 'col2' + }); + editCommand.columnDeletions['table1'] = ['col1']; + }, + expectation: [] + }, + { + name: 'editing a new column in a new table removes the column edit', + setup: () => { + editCommand.tableAdditions.push({ name: 'table1' }); + createAddition(column); + createAddition({ + ...column, + name: 'col8', + originalName: 'col8' + }); + createEdit({ + ...column, + name: 'col2' + }); + createEdit({ + ...column, + name: 'col3' + }); + }, + expectation: [ + { + create_table: { + name: 'table1', + columns: [ + { + name: 'col3', + type: 'text', + nullable: true, + unique: false, + check: { + constraint: 'LENGTH("col3") <= 2048', + name: 'table1_xata_string_length_col3' + }, + comment: '{"xata.type":"string"}', + default: undefined, + references: undefined + }, + { + name: 'col8', + type: 'text', + nullable: true, + unique: false, + check: { + constraint: 'LENGTH("col8") <= 2048', + name: 'table1_xata_string_length_col8' + }, + comment: '{"xata.type":"string"}', + default: undefined, + references: undefined, + up: undefined + } + ] + } + } + ] + } +]; + +describe('edits to migrations', () => { + const testWithOnly = testCases.some(({ only }) => only); + testWithOnly + ? testCases.filter(({ only }) => only).forEach(({ name, setup, expectation }) => runTest(name, setup, expectation)) + : null; + !testWithOnly ? testCases.forEach(({ name, setup, expectation }) => runTest(name, setup, expectation)) : null; +}); diff --git a/cli/src/commands/schema/edit.ts b/cli/src/commands/schema/edit.ts index eddb5f20b..6eee99330 100644 --- a/cli/src/commands/schema/edit.ts +++ b/cli/src/commands/schema/edit.ts @@ -1,107 +1,56 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { Flags } from '@oclif/core'; +import { BaseCommand } from '../../base.js'; +import { Config, Flags } from '@oclif/core'; import { Schemas } from '@xata.io/client'; -import { parseSchemaFile } from '@xata.io/codegen'; -import { isValidEmail } from '@xata.io/importer'; +import { + OpAddColumn, + OpAlterColumn, + OpCreateTable, + OpDropColumn, + OpDropConstraint, + OpDropTable, + OpRenameTable, + PgRollMigration, + PgRollMigrationDefinition, + PgRollOperation +} from '@xata.io/pgroll'; import chalk from 'chalk'; import enquirer from 'enquirer'; -import { getEditor } from 'env-editor'; -import { readFile, writeFile } from 'fs/promises'; -import tmp from 'tmp'; -import which from 'which'; -import { BaseCommand } from '../../base.js'; -import { getBranchDetailsWithPgRoll } from '../../migrations/pgroll.js'; -import { isNil, reportBugURL } from '../../utils.js'; -import Codegen from '../codegen/index.js'; -import Pull from '../pull/index.js'; +import { + exhaustiveCheck, + generateLinkReference, + getBranchDetailsWithPgRoll, + isBranchPgRollEnabled, + requiresUpArgument, + updateConstraint, + updateLinkComment, + waitForMigrationToFinish, + xataColumnTypeToPgRoll, + xataColumnTypeToPgRollComment, + xataColumnTypeToPgRollConstraint, + xataColumnTypeToZeroValue +} from '../../migrations/pgroll.js'; +import EditSchemaOld from './edit-old.js'; -// The enquirer library has type definitions but they are very poor const { Select, Snippet, Confirm } = enquirer as any; -type Schema = Schemas.Schema; -type Table = Schema['tables'][0]; -type Column = Table['columns'][0]; - -type EditableColumn = Column & { - added?: boolean; - deleted?: boolean; - initialName?: string; - description?: string; -}; - -type EditableTable = Table & { - added?: string; - deleted?: boolean; - initialName?: string; - columns: EditableColumn[]; -}; - -type ColumnEditState = { - initial: { - name: string; - type: string; - link: string | undefined; - vectorDimension: string | undefined; - notNull: string; - defaultValue: string; - unique: string; - description: string | undefined; - }; - values: { - name?: string; - type?: string; - link?: string; - vectorDimension?: string; - notNull?: string; - defaultValue?: string; - unique?: string; - description?: string; - }; -}; - -const types = ['string', 'int', 'float', 'bool', 'text', 'multiple', 'link', 'email', 'datetime', 'vector', 'json']; -const typesList = types.join(', '); -const identifier = /^[a-zA-Z0-9-_~]+$/; - -const uniqueUnsupportedTypes = ['text', 'multiple', 'vector', 'json']; -const defaultValueUnsupportedTypes = ['multiple', 'link', 'vector']; -const notNullUnsupportedTypes = defaultValueUnsupportedTypes; - -const waitFlags: Record = { - code: '-w', - 'code-insiders': '-w', - vscodium: '-w', - sublime: '-w', - textmate: '-w', - atom: '--wait', - webstorm: '--wait', - intellij: '--wait', - xcode: '-w' -}; - -type SelectChoice = { - name: - | { - type: 'space' | 'schema' | 'add-table' | 'migrate'; - } - | { - type: 'add-column' | 'edit-table'; - table: EditableTable; - } - | { - type: 'edit-column'; - table: EditableTable; - column: EditableColumn; - }; - message: string; - role?: string; - choices?: SelectChoice[]; - disabled?: boolean; - hint?: string; -}; +const xataTypes = [ + 'string', + 'int', + 'float', + 'bool', + 'text', + 'multiple', + 'link', + 'email', + 'datetime', + 'vector', + 'json', + 'file', + 'file[]' +]; export default class EditSchema extends BaseCommand { - static description = 'Edit the schema of the current database'; + static description = 'Edit the schema'; static examples = []; @@ -115,176 +64,121 @@ export default class EditSchema extends BaseCommand { static args = {}; - branchDetails: Schemas.DBBranch | undefined; - tables: EditableTable[] = []; + branchDetails: BranchSchemaFormatted; workspace!: string; region!: string; database!: string; branch!: string; - selectItem: EditableColumn | EditableTable | null = null; + tableAdditions: AddTablePayload['table'][] = []; + tableEdits: EditTablePayload['table'][] = []; + tableDeletions: DeleteTablePayload[] = []; - async run(): Promise { - const { flags } = await this.parseCommand(); + columnEdits: ColumnEdits = {}; + columnAdditions: ColumnAdditions = {}; + columnDeletions: DeleteColumnPayload = {}; - if (flags.source) { - this.warn( - `This way of editing the schema doesn't detect renames of tables or columns. They are interpreted as deleting/adding tables and columns. -Beware that this can lead to ${chalk.bold( - 'data loss' - )}. Other ways of editing the schema that do not have this limitation are: -* run the command without ${chalk.bold('--source')} -* edit the schema in the Web UI. Use ${chalk.bold('xata browse')} to open the Web UI in your browser.` - ); - this.log(); - } + currentMigration: PgRollMigration = { operations: [] }; - const { workspace, region, database, branch } = await this.getParsedDatabaseURLWithBranch(flags.db, flags.branch); - this.workspace = workspace; - this.region = region; - this.database = database; - this.branch = branch; - - const xata = await this.getXataClient(); - const branchDetails = await getBranchDetailsWithPgRoll(xata, { workspace, region, database, branch }); - if (!branchDetails) this.error('Could not get the schema from the current branch'); - - if (flags.source) { - await this.showSourceEditing(branchDetails); - } else { - await this.showInteractiveEditing(branchDetails); - } - } - - async showSourceEditing(branchDetails: Schemas.DBBranch) { - const env = process.env.EDITOR || process.env.VISUAL; - if (!env) { - this.error( - `Could not find an editor. Please set the environment variable ${chalk.bold('EDITOR')} or ${chalk.bold( - 'VISUAL' - )}` - ); - } - - const info = await getEditor(env); - // This honors the env value. For `code-insiders` for example, we don't want `code` to be used instead. - const binary = which.sync(env, { nothrow: true }) ? env : info.binary; - - const tmpobj = tmp.fileSync({ prefix: 'schema-', postfix: 'source.json' }); - // TODO: add a $schema to the document to allow autocomplete in editors such as vscode - await writeFile(tmpobj.name, JSON.stringify(branchDetails.schema, null, 2)); - - const waitFlag = waitFlags[info.id] || waitFlags[env]; - - if (!info.isTerminalEditor && !waitFlag) { - this.error(`The editor ${chalk.bold(env)} is a graphical editor that is not supported.`, { - suggestions: [ - `Set the ${chalk.bold('EDITOR')} or ${chalk.bold('VISUAL')} variables to a different editor`, - `Open an issue at ${reportBugURL(`Support \`${info.binary}\` editor for schema editing`)}` - ] - }); - } - - const args = [waitFlag, tmpobj.name].filter(Boolean); - await this.runCommand(binary, args); - - const newSchema = await readFile(tmpobj.name, 'utf8'); - const result = parseSchemaFile(newSchema); - if (!result.success) { - this.printZodError(result.error); - this.error('The schema is not valid. See the errors above'); - } - - await this.deploySchema(this.workspace, this.region, this.database, this.branch, result.data); - - // Run pull to retrieve remote migrations - await Pull.run([this.branch]); - } + activeIndex: number = 0; - async showInteractiveEditing(branchDetails: Schemas.DBBranch) { - this.branchDetails = branchDetails; - this.tables = this.branchDetails.schema.tables; - await this.showSchema(); - } - - async showSchema() { + async showSchemaEdit() { this.clear(); + const tableChoices: SelectChoice[] = []; + const select = new Select({ + message: 'Schema for database test:main', + initial: this.activeIndex, + choices: [ + { + name: { type: 'schema' }, + message: 'Tables', + role: 'heading', + choices: tableChoices + } + ], + footer: + 'Use the ↑ ↓ arrows to move across the schema, enter to edit or add things, delete or backspace to delete things.' + }); - const choices: SelectChoice[] = [ - this.createSpace() // empty space + const tables = [ + ...(this.branchDetails?.schema?.tables ?? []), + ...this.tableAdditions.map((addition) => ({ + name: addition.name, + columns: [] + })) ]; - const flatChoices = [...choices]; - - const tableChoices: SelectChoice[] = []; - const schema: SelectChoice = { - name: { type: 'schema' }, - message: 'Tables', - role: 'heading', - choices: tableChoices - }; - choices.push(schema); - flatChoices.push(schema); - let index = 0; - for (const table of this.tables) { - const columnChoices: SelectChoice[] = table.columns.map((column, i) => { - if (this.selectItem === column) index = flatChoices.length + i + 1; - return { - name: { type: 'edit-column', column, table }, - message: this.getMessageForColumn(table, column) - }; - }); - columnChoices.push({ - message: `${chalk.green('+')} Add a column`, - name: { type: 'add-column', table }, - disabled: table.deleted + for (const table of tables) { + tableChoices.push({ + name: { type: 'edit-table', table: { name: table.name, newName: table.name } }, + message: this.renderTableMessage(table.name), + choices: [ + ...table.columns.map((column) => { + const col = formatSchemaColumnToColumnData({ + column: { ...column, originalName: column.name }, + tableName: table.name + }); + return { + name: { + type: 'edit-column', + column: col + }, + message: this.renderColumnMessage({ column: col }), + disabled: editTableDisabled(table.name, this.tableDeletions) + } as SelectChoice; + }), + ...Object.values(this.columnAdditions[table.name] ?? []).map((column) => { + const formatted = { ...column, tableName: table.name, originalName: column.name }; + return { + name: { type: 'edit-column', column: formatted }, + message: this.renderColumnMessage({ column: formatted }), + disabled: editTableDisabled(table.name, this.tableDeletions) + } as SelectChoice; + }), + { + name: { + type: 'add-column', + tableName: table.name, + column: { originalName: '', tableName: table.name, name: '', type: '', unique: false, nullable: true } + }, + message: `${chalk.green('+')} Add a column`, + disabled: editTableDisabled(table.name, this.tableDeletions), + hint: 'Add a column to a table' + } + ] }); - const tableChoice: SelectChoice = { - name: { type: 'edit-table', table }, - message: this.getMessageForTable(table), - choices: columnChoices - }; - tableChoices.push(tableChoice); - if (this.selectItem === table) index = flatChoices.length; - flatChoices.push(tableChoice); - flatChoices.push(...columnChoices); - tableChoices.push(this.createSpace()); - flatChoices.push(this.createSpace()); } - choices.push({ message: `${chalk.green('+')} Add a table`, name: { type: 'add-table' } }); - choices.push(this.createSpace()); - - const overview = this.getOverview(); - choices.push({ - message: `${chalk.green('►')} Run migration${overview ? ':' : ''}`, - name: { type: 'migrate' }, - disabled: !overview, - hint: overview || 'No changes made so far' - }); - choices.push(this.createSpace()); + tableChoices.push( + createSpace(), + { + message: `${chalk.green('+')} Add a table`, + name: { type: 'add-table', table: { name: '' } } + }, + { + message: `${chalk.green('►')} Run migration`, + name: { type: 'migrate' }, + hint: 'Run the migration' + } + ); - const select = new Select({ - message: 'Schema for database test:main', - initial: index, - choices, - footer: - 'Use the ↑ ↓ arrows to move across the schema, enter to edit or add things, delete or backspace to delete things.' - }); select.on('keypress', async (char: string, key: { name: string; action: string }) => { - const flatChoice = flatChoices[select.state.index]; + this.activeIndex = select.state.index; + const selectedItem = select.state.choices[select.state.index]; try { if (key.name === 'backspace' || key.name === 'delete') { - if (!flatChoice) return; // add table is not here for example - const choice = flatChoice.name; + if (!selectedItem) return; + const choice = selectedItem.name; if (typeof choice !== 'object') return; - if (choice.type === 'edit-table') { await select.cancel(); - await this.deleteTable(choice.table); - } else if (choice.type === 'edit-column' && !choice.table.deleted) { + await this.toggleTableDelete({ initialTableName: choice.table.name }); + await this.showSchemaEdit(); + } + if (choice.type === 'edit-column') { await select.cancel(); - await this.deleteColumn(choice.column, choice.table); + await this.toggleColumnDelete(choice); + await this.showSchemaEdit(); } } } catch (err) { @@ -294,596 +188,992 @@ Beware that this can lead to ${chalk.bold( }); try { - const result = await select.run(); - - if (result.type === 'edit-column') { - await this.showColumnEdit(result.column, result.table); + const result: SelectChoice['name'] = await select.run(); + if (result.type === 'add-table') { + await this.showAddTable(result.table); + } else if (result.type === 'edit-column') { + if (editColumnDisabled(result.column, this.columnDeletions)) { + await this.showSchemaEdit(); + } else { + await this.showColumnEdit(result.column); + } } else if (result.type === 'edit-table') { - await this.showTableEdit(result.table); + if (editTableDisabled(result.table.name, this.tableDeletions)) { + await this.showSchemaEdit(); + } else { + await this.showTableEdit({ initialTableName: result.table.name }); + } } else if (result.type === 'add-column') { - await this.showColumnEdit(null, result.table); - } else if (result.type === 'add-table') { - await this.showTableEdit(null); - } else if (result.type === 'delete-table') { - await this.deleteTable(result.table); + await this.showAddColumn(result); } else if (result.type === 'migrate') { await this.migrate(); - await Codegen.runIfConfigured(this.projectConfig); - process.exit(0); + } else if (result.type === 'schema' || result.type === 'space') { + await this.showSchemaEdit(); + } else { + exhaustiveCheck(result.type); } - } catch (err) { - if (err) throw err; - // if not, user cancelled + } catch (error) { + if (error) throw error; } + this.clear(); + } + async migrate() { this.clear(); + this.currentMigration = { operations: [] }; + this.currentMigration.operations = editsToMigrations(this); + const valid = validateMigration(this.currentMigration); + if (valid.success) { + const prompt = new Confirm({ + name: 'question', + message: `Are you sure you want to run the migration? ${JSON.stringify(this.currentMigration, null, 2)}` + }); + try { + const answer = await prompt.run(); + if (!answer) { + await this.showSchemaEdit(); + return; + } + const xata = await this.getXataClient(); + + const submitMigrationRessponse = await xata.api.migrations.applyMigration({ + pathParams: { + workspace: this.workspace, + region: this.region, + dbBranchName: `${this.database}:${this.branch}` + }, + body: { ...this.currentMigration, adaptTables: true } + }); + + await waitForMigrationToFinish( + xata.api, + this.workspace, + this.region, + this.database, + this.branch, + submitMigrationRessponse.jobID + ); + + const alterLinkColumns = this.currentMigration.operations.reduce((acc, op) => { + const operation = updateLinkComment(this.branchDetails, op); + if (operation) acc.push(...operation); + return acc; + }, [] as PgRollOperation[]); + + if (alterLinkColumns.length > 0) { + const { jobID: alterLinkColumnId } = await xata.api.migrations.applyMigration({ + pathParams: { + workspace: this.workspace, + region: this.region, + dbBranchName: `${this.database}:${this.branch}` + }, + body: { operations: alterLinkColumns } + }); + + await waitForMigrationToFinish( + xata.api, + this.workspace, + this.region, + this.database, + this.branch, + alterLinkColumnId + ); + } + + const constraintRenames = this.currentMigration.operations.reduce((acc, op) => { + const operation = updateConstraint(this.branchDetails, op); + if (operation) acc.push(...operation); + return acc; + }, [] as PgRollOperation[]); + + if (constraintRenames.length > 0) { + const { jobID: constraintRenameJobID } = await xata.api.migrations.applyMigration({ + pathParams: { + workspace: this.workspace, + region: this.region, + dbBranchName: `${this.database}:${this.branch}` + }, + body: { operations: constraintRenames } + }); + + await waitForMigrationToFinish( + xata.api, + this.workspace, + this.region, + this.database, + this.branch, + constraintRenameJobID + ); + } + + this.success('Migration completed!'); + process.exit(0); + } catch (err) { + if (err) throw err; + // User cancelled + await this.showSchemaEdit(); + return; + } + } else { + this.logJson(this.currentMigration); + this.toErrorJson('Migration is invalid:' + valid.error.errors.flatMap((e) => e.message).join('\n')); + } } - createSpace(): SelectChoice { - return { name: { type: 'space' }, message: ' ', role: 'heading' }; + getColumnNameEdit({ column }: { column: EditColumnPayload['column'] }) { + return this.columnEdits[column.tableName]?.[column.originalName]?.name; } - getMessageForTable(table: EditableTable) { - if (table.deleted) return `• ${chalk.red.strikethrough(table.name)}`; - if (table.added) return `• ${chalk.green(table.name)}`; - if (table.initialName) return `• ${chalk.bold(table.name)} ${chalk.yellow.strikethrough(table.initialName)}`; - return `• ${chalk.bold(table.name)}`; + getColumnNullable({ column }: { column: EditColumnPayload['column'] }) { + return this.columnEdits[column.tableName]?.[column.originalName]?.nullable ?? column.nullable; } - getMessageForColumn(table: EditableTable, column: EditableColumn) { - const linkedTable = this.tables.find((t) => (t.initialName || t.name) === column.link?.table); - function getType() { - if (!linkedTable) return chalk.gray.italic(column.type); - return `${chalk.gray.italic(column.type)} → ${chalk.gray.italic(linkedTable.name)}`; - } + getColumnUnique({ column }: { column: EditColumnPayload['column'] }) { + return this.columnEdits[column.tableName]?.[column.originalName]?.unique ?? column.unique; + } + + renderColumnMessage({ column }: { column: EditColumnPayload['column'] }) { + const maybeNewColumnName = this.getColumnNameEdit({ column }); + const isColumnDeleted = Object.entries(this.columnDeletions) + .filter((entry) => entry[0] === column.tableName) + .find((entry) => entry[1].includes(column.originalName)); + const isTableDeleted = this.tableDeletions.find(({ name }) => name === column.tableName); + + const unique = () => { + const currentUniqueValue = this.getColumnUnique({ column }); + if (currentUniqueValue !== column.unique) { + return currentUniqueValue ? chalk.green('unique') : chalk.green('not unique'); + } + return currentUniqueValue ? chalk.gray.italic('unique') : ''; + }; + + const nullable = () => { + const currentNullableValue = this.getColumnNullable({ column }); + if (currentNullableValue !== column.nullable) { + return currentNullableValue ? chalk.green('nullable') : chalk.green('not nullable'); + } + return currentNullableValue ? '' : chalk.gray.italic('not nullable'); + }; + const metadata = [ - getType(), - column.unique ? chalk.gray.italic('unique') : '', - column.notNull ? chalk.gray.italic('not null') : '', + `${chalk.gray.italic(column.type)}${column.type === 'link' ? ` → ${chalk.gray.italic(column.link?.table)}` : ''}`, + unique(), + nullable(), column.defaultValue ? chalk.gray.italic(`default: ${column.defaultValue}`) : '' ] .filter(Boolean) .join(' '); - if (table.deleted || column.deleted || linkedTable?.deleted) - return `- ${chalk.red.strikethrough(column.name)} (${metadata})`; - if (table.added || column.added) return `- ${chalk.green(column.name)} (${metadata})`; - if (column.initialName) - return `- ${chalk.cyan(column.name)} ${chalk.yellow.strikethrough(column.initialName)} (${metadata})`; - return `- ${chalk.cyan(column.name)} (${metadata})`; + + if (isColumnDeleted || isTableDeleted) { + return ` - ${chalk.red.strikethrough(column.originalName)} (${metadata})`; + } + // Checking names are not the same because it is possible only nullable or unique changed + if (maybeNewColumnName && maybeNewColumnName !== column.originalName) { + return ` - ${chalk.yellow.strikethrough(column.originalName)} -> ${chalk.bold(maybeNewColumnName)} (${metadata})`; + } + return `- ${chalk.cyan(column.originalName)} (${metadata})`; } - getOverview() { - const info = { - tables: { added: 0, deleted: 0, modified: 0 }, - columns: { added: 0, deleted: 0, modified: 0 } - }; - for (const table of this.tables) { - if (table.added) info.tables.added++; - else if (table.deleted) info.tables.deleted++; - else if (table.initialName) info.tables.modified++; - - for (const column of table.columns) { - const linkedTable = this.tables.find((t) => (t.initialName || t.name) === column.link?.table); - if (table.added || column.added) info.columns.added++; - else if (table.deleted || column.deleted || linkedTable?.deleted) info.columns.deleted++; - else if (column.initialName) info.columns.modified++; + renderTableNameEdited(tableName: string) { + return this.tableEdits.find((edit) => edit.name === tableName)?.newName; + } + + renderTableMessage(originalName: string, newTable: boolean = false) { + const tableEdit = this.tableEdits.find(({ name }) => name === originalName); + const tableDelete = this.tableDeletions.find(({ name }) => name === originalName); + if (tableDelete) { + return `• ${chalk.red.strikethrough(originalName)}`; + } + if (tableEdit) { + return `• ${chalk.yellow.strikethrough(originalName)} -> ${chalk.bold( + this.renderTableNameEdited(originalName) ?? originalName + )}`; + } + return newTable ? `• ${chalk.bold(originalName)}` : `• ${chalk.bold(originalName)}`; + } + + async run(): Promise { + const { flags } = await this.parseCommand(); + + const { workspace, region, database, branch } = await this.getParsedDatabaseURLWithBranch(flags.db, flags.branch); + this.workspace = workspace; + this.region = region; + this.database = database; + this.branch = branch; + + const config = await Config.load(); + + const xata = await this.getXataClient(); + const branchDetails = await getBranchDetailsWithPgRoll(xata, { + workspace, + region, + database, + branch + }); + if (!branchDetails) this.error('Could not get the schema from the current branch'); + + if (isBranchPgRollEnabled(branchDetails)) { + if (flags.source) { + this.warn('Schema source editing is not supported yet. Please run the command without the --source flag.'); + process.exit(0); + } else { + this.branchDetails = branchDetails as any; + await this.showSchemaEdit(); } + } else { + const editOld = new EditSchemaOld(this.argv, config); + editOld.launch({ + workspace: this.workspace, + region: this.region, + database: this.database, + branch: this.branch + }); } + } - const tablesOverview = [ - info.tables.added ? `${chalk.green(`+${info.tables.added}`)}` : null, - info.tables.deleted ? `${chalk.red(`-${info.tables.deleted}`)}` : null, - info.tables.modified ? `${chalk.yellow(`·${info.tables.modified}`)}` : null - ].filter(Boolean); + clear() { + process.stdout.write('\x1b[2J'); + process.stdout.write('\x1b[0f'); + } - const columnsOverview = [ - info.columns.added ? `${chalk.green(`+${info.columns.added}`)}` : null, - info.columns.deleted ? `${chalk.red(`-${info.columns.deleted}`)}` : null, - info.columns.modified ? `${chalk.yellow(`·${info.columns.modified}`)}` : null - ].filter(Boolean); + footer() { + return '\nUse the ↑ ↓ arrows to move across fields, enter to submit and escape to cancel.'; + } - const messages = [ - tablesOverview.length > 0 ? `${tablesOverview.join(', ')} tables` : null, - columnsOverview.length > 0 ? `${columnsOverview.join(', ')} columns` : null - ].filter(Boolean); + async toggleTableDelete({ initialTableName }: { initialTableName: string }) { + const indexOfExistingEntry = this.tableDeletions.findIndex(({ name }) => name === initialTableName); + indexOfExistingEntry > -1 + ? this.tableDeletions.splice(indexOfExistingEntry, 1) + : this.tableDeletions.push({ name: initialTableName }); + } - return messages.join(', '); + async toggleColumnDelete({ column }: { column: EditColumnPayload['column'] }) { + const existingEntryIndex = this.columnDeletions[column.tableName]?.findIndex( + (name) => name === column.originalName + ); + if (existingEntryIndex > -1) { + this.columnDeletions[column.tableName].splice(existingEntryIndex, 1); + } else { + !this.columnDeletions[column.tableName] + ? (this.columnDeletions[column.tableName] = [column.originalName]) + : this.columnDeletions[column.tableName].push(column.originalName); + } } - async showColumnEdit(column: EditableColumn | null, table: EditableTable) { + async showColumnEdit(column: EditColumnPayload['column']) { this.clear(); - const isColumnAdded = !column || column?.added; const template = ` - name: \${name} - type: \${type} - link: \${link} -vectorDimension: \${vectorDimension} - description: \${description} - unique: \${unique} - notNull: \${notNull} - defaultValue: \${defaultValue}`; - - const initial: ColumnEditState['initial'] = { - name: column?.name || '', - type: column?.type || '', - link: isColumnAdded ? '' : column?.link?.table, - vectorDimension: column?.vector?.dimension ? `${column?.vector?.dimension}` : undefined, - notNull: column?.notNull ? 'true' : 'false', - defaultValue: column?.defaultValue || '', - unique: column?.unique ? 'true' : 'false', - description: isColumnAdded ? '' : column?.description - }; - const snippet: any = new Snippet({ - message: column?.name || 'a new column', - initial, + name: \${name}, + column: ${column.originalName}, + nullable: \${nullable}, + unique: \${unique}, + `; + // TODO support default https://github.com/xataio/pgroll/issues/327 + // TODO support changing type https://github.com/xataio/pgroll/issues/328 + const snippet = new Snippet({ + message: 'Edit a column', fields: [ { name: 'name', - message: 'The column name', - validate(value: string | undefined, state: ColumnEditState, item: unknown, index: number) { - if (!identifier.test(value || '')) { - return snippet.styles.danger(`Column name has to match ${identifier}`); - } - return true; - } + message: 'The name of the column', + initial: this.getColumnNameEdit({ column }) ?? column.originalName, + validate: this.validateColumnName }, { - name: 'type', - message: `The column type (${typesList})`, - validate(value: string | undefined, state: ColumnEditState, item: unknown, index: number) { - if (!isColumnAdded && value !== state.initial.type) { - return `Cannot change the type of existing columns`; - } - if (!value || !types.includes(value)) { - return `Type needs to be one of ${typesList}`; - } - return true; - } + name: 'nullable', + message: `Whether the column can be null.`, + initial: this.getColumnNullable({ column }) ? 'true' : 'false', + validate: this.validateColumnNullable }, { - name: 'link', - message: 'Linked table. Only for columns that are links', - validate( - value: string | undefined, - state: ColumnEditState, - item: { value: string | undefined }, - index: number - ) { - if (!isColumnAdded && value !== state.initial.link) { - return `Cannot change the link of existing link columns`; - } - if (state.values.type === 'link') { - if (!value) { - return 'The link field must be filled for columns of type `link`'; - } - } else if (value) { - return 'The link field must not be filled unless the type of the column is `link`'; - } - return true; - } + name: 'unique', + message: `Whether the column is unique.`, + initial: this.getColumnUnique({ column }) ? 'true' : 'false', + validate: this.validateColumnUnique + } + ], + footer: this.footer, + template + }); + + try { + const { values } = await snippet.run(); + const existingEntry = this.columnEdits[column.tableName]?.[column.originalName]; + + const unchanged = + column.originalName === values.name && + column.nullable === parseBoolean(values.nullable) && + column.unique === parseBoolean(values.unique); + if (unchanged && existingEntry) { + delete this.columnEdits[column.tableName][column.originalName]; + } else if (!unchanged && existingEntry) { + existingEntry.name = values.name; + existingEntry.nullable = parseBoolean(values.nullable) ?? true; + existingEntry.unique = parseBoolean(values.unique) ?? false; + } else if (!unchanged && !existingEntry) { + if (!this.columnEdits[column.tableName]) this.columnEdits[column.tableName] = {}; + if (!this.columnEdits[column.tableName][column.originalName]) + this.columnEdits[column.tableName][column.originalName] = {} as any; + this.columnEdits[column.tableName][column.originalName] = formatSchemaColumnToColumnData({ + column: { + ...column, + ...values, + originalName: column.originalName, + notNull: parseBoolean(values.nullable) === false ? true : false, + unique: parseBoolean(values.unique) ? true : false + }, + tableName: column.tableName + }); + } + await this.showSchemaEdit(); + } catch (err) { + if (err) throw err; + // User cancelled + await this.showSchemaEdit(); + return; + } + } + + async showAddColumn({ + tableName, + column + }: { + tableName: AddColumnPayload['tableName']; + column: AddColumnPayload['column']; + }) { + this.clear(); + const template = ` + name: \${name}, + nullable: \${nullable}, + unique: \${unique}, + type: \${type}, + default: \${default} + link: \${link} + vectorDimension: \${vectorDimension} + defaultPublicAccess: \${defaultPublicAccess} + }, + table: ${tableName}`; + + const snippet = new Snippet({ + message: 'Add a column', + fields: [ + { + name: 'name', + message: 'The name of the column', + validate: this.validateColumnName }, { - name: 'vectorDimension', - message: 'Vector Dimension. Only for columns that are vectors', - validate( - value: string | undefined, - state: ColumnEditState, - item: { value: string | undefined }, - index: number - ) { - if (!isColumnAdded && value !== state.initial.vectorDimension) { - return `Cannot change the vector dimension of existing vector columns`; - } - if (state.values.type === 'vector') { - if (!value) { - return 'The vectorDimension field must be filled for columns of type `vector`'; - } - } else if (value) { - return 'The vectorDimension field must not be filled unless the type of the column is `vector`'; - } - return true; + name: 'type', + message: `The type of the column ${xataTypes}`, + validate: (value: string) => { + if (value === undefined) return 'Type cannot be undefined'; + if (emptyString(value)) return 'Type cannot be empty'; + if (!xataTypes.includes(value)) + return 'Invalid xata type. Please specify one of the following: ' + xataTypes; } }, + { + name: 'nullable', + message: `Whether the column can be null.`, + validate: this.validateColumnNullable + }, { name: 'unique', - message: 'Whether the column is unique (true/false)', - validate(value: string | undefined, state: ColumnEditState, item: unknown, index: number) { - if (!isColumnAdded && parseBoolean(value) !== parseBoolean(state.initial.unique)) { - return `Cannot change unique for existing columns`; - } - const validateOptionalBooleanResult = validateOptionalBoolean(value); - if (validateOptionalBooleanResult !== true) { - return validateOptionalBooleanResult; - } - const validateUniqueResult = validateUnique(value, state); - if (validateUniqueResult !== true) { - return validateUniqueResult; - } - return true; - } + message: `Whether the column is unique.`, + validate: this.validateColumnUnique }, { - name: 'notNull', - message: 'Whether the column is not nullable (true/false)', - validate(value: string | undefined, state: ColumnEditState, item: unknown, index: number) { - if (!isColumnAdded && parseBoolean(value) !== parseBoolean(state.initial.notNull)) { - return `Cannot change notNull for existing columns`; - } - const validateOptionalBooleanResult = validateOptionalBoolean(value); - if (validateOptionalBooleanResult !== true) { - return validateOptionalBooleanResult; - } - const validateNotNullResult = validateNotNull(value, state); - if (validateNotNullResult !== true) { - return validateNotNullResult; - } + name: 'default', + message: `The default for the column.` + }, + { + name: 'link', + message: 'Linked table. Only required for columns that are links. Will be ignored if type is not link.', + validate: (value: string, state: ValidationState) => { + const columnType = state.items.find(({ name }) => name === 'type')?.input; + if ((value === undefined || emptyString(value)) && columnType === 'link') + return 'Cannot be empty string when the type is link'; return true; } }, { - name: 'description', - message: 'An optional column description', - validate(value: string | undefined, state: ColumnEditState, item: unknown, index: number) { - if (!isColumnAdded && value !== state.initial.description) { - return `Cannot change description for existing columns`; - } + name: 'vectorDimension', + message: 'Vector dimension. Only required for vector columns. Will be ignored if type is not vector.', + validate: (value: string, state: ValidationState) => { + const columnType = state.items.find(({ name }) => name === 'type')?.input; + if ((value === undefined || emptyString(value)) && columnType === 'vector') + return 'Cannot be empty string when the type is vector'; return true; } }, { - name: 'defaultValue', - message: 'Default value', - validate(rawDefaultValue: string | undefined, state: ColumnEditState, item: unknown, index: number) { - if ( - !isColumnAdded && - state.values.type && - parseDefaultValue(state.values.type, rawDefaultValue) !== - parseDefaultValue(state.values.type, state.initial.defaultValue) - ) { - return `Cannot change defaultValue for existing columns`; - } - if (state.values.type) { - const isNotNull = parseBoolean(state.values.notNull) === true; - const defaultValue = parseDefaultValue(state.values.type, rawDefaultValue); - if (isNotNull && (!rawDefaultValue || rawDefaultValue.length === 0)) { - return 'defaultValue must be set for `notNull: true` columns'; - } - if (rawDefaultValue && rawDefaultValue.length > 0 && defaultValue === undefined) { - return `Invalid defaultValue for Type: ${state.values.type}`; - } - } + name: 'defaultPublicAccess', + message: + 'Default public access. Only required for file or file[] columns. Will be ignored if type is not file or file[].', + validate: (value: string, state: ValidationState) => { + const columnType = state.items.find(({ name }) => name === 'type')?.input; + if ((value === undefined || emptyString(value)) && (columnType === 'file' || columnType === 'file[]')) + return 'Cannot be empty string when the type is file or file[]. Please input true or false'; return true; } } ], - footer() { - return '\nUse the ↑ ↓ arrows to move across fields, enter to submit and escape to cancel.'; - }, + footer: this.footer, template }); - try { const { values } = await snippet.run(); - const unique = parseBoolean(values.unique); - const notNull = parseBoolean(values.notNull); - const col: Column = { - name: values.name, - type: values.type, - link: values.link && values.type === 'link' ? { table: values.link } : undefined, - vector: values.vectorDimension ? { dimension: parseInt(values.vectorDimension, 10) } : undefined, - unique: unique || undefined, - notNull: notNull || undefined, - defaultValue: parseDefaultValue(values.type, values.defaultValue) - // TODO: add description once the backend supports it - // description: values.description - }; - if (column) { - if (!column.initialName && !column.added && column.name !== values.name) { - column.initialName = column.name; - } - Object.assign(column, col); - if (column.name === column.initialName) { - delete column.initialName; - } - } else { - table.columns.push({ - ...col, - added: true - }); - // Override the variable to use it when redefining this.selectItem below - column = table.columns[table.columns.length - 1]; - } + if (!this.columnAdditions[tableName]) this.columnAdditions[tableName] = {}; + if (!this.columnAdditions[tableName][values.name]) this.columnAdditions[tableName][values.name] = {} as any; + this.columnAdditions[tableName][values.name] = formatSchemaColumnToColumnData({ + column: { + ...column, + ...values, + originalName: column.originalName, + 'file[]': + values.type === 'file[]' + ? { defaultPublicAccess: parseBoolean(values.defaultPublicAccess) ?? false } + : undefined, + file: + values.type === 'file' + ? { defaultPublicAccess: parseBoolean(values.defaultPublicAccess) ?? false } + : undefined, + vector: values.vectorDimension + ? { + dimension: values.vectorDimension + } + : undefined, + link: values.link + ? { + table: values.link + } + : undefined, + defaultValue: values.default, + notNull: parseBoolean(values.nullable) === false ? true : false, + unique: parseBoolean(values.unique) ? true : false + }, + tableName: column.tableName + }); + await this.showSchemaEdit(); } catch (err) { if (err) throw err; - // if not, user cancelled + // User cancelled + await this.showSchemaEdit(); + return; } - - this.selectItem = column; - await this.showSchema(); } - async showTableEdit(table: EditableTable | null) { + async showAddTable({ name }: { name: AddTablePayload['table']['name'] }) { this.clear(); - const snippet = new Snippet({ - message: table ? table.name : 'a new table', - initial: { - name: table ? table.name : '' - }, + message: 'Add a table', + initial: { name: name }, fields: [ { name: 'name', message: 'The table name', - validate(value: string, state: unknown, item: unknown, index: number) { - if (!identifier.test(value || '')) { - return snippet.styles.danger(`Table name has to match ${identifier}`); - } - return true; - } - }, + validate: this.validateTableName + } + ], + footer: this.footer, + template: ` + Name: \${name} + ` + }); + + try { + const answer: { values: { name: string } } = await snippet.run(); + this.tableAdditions.push({ name: answer.values.name }); + } catch (err) { + if (err) throw err; + } + await this.showSchemaEdit(); + } + + async showTableEdit({ initialTableName }: { initialTableName: string }) { + this.clear(); + const snippet = new Snippet({ + message: 'Edit table name', + fields: [ { - name: 'description', - message: 'An optional table description' + name: 'name', + message: 'The table name', + initial: this.renderTableNameEdited(initialTableName) ?? initialTableName, + validate: this.validateTableName } ], - footer() { - return '\nUse the ↑ ↓ arrows to move across fields, enter to submit and escape to cancel.'; - }, + footer: this.footer, template: ` Name: \${name} - Description: \${description}` + ` }); try { - const answer = await snippet.run(); - if (table) { - if (!table.initialName && !table.added && table.name !== answer.values.name) { - table.initialName = table.name; - } - Object.assign(table, answer.values); - if (table.name === table.initialName) { - delete table.initialName; - } - } else { - this.tables.push({ - ...answer.values, - columns: [], - added: true - }); - // Override the variable to use it when redefining this.selectItem below - table = this.tables[this.tables.length - 1]; + const answer: { values: { name: string } } = await snippet.run(); + const existingEntry = this.tableEdits.find(({ name }) => name === initialTableName); + const changed = answer.values.name !== initialTableName; + if (existingEntry && changed) { + existingEntry.newName = answer.values.name; + } else if (existingEntry && !changed) { + this.tableEdits = this.tableEdits.filter(({ name }) => name !== initialTableName); + } else if (!existingEntry && changed) { + this.tableEdits.push({ name: initialTableName, newName: answer.values.name }); } + await this.showSchemaEdit(); } catch (err) { if (err) throw err; - // if not, user cancelled + // User cancelled + await this.showSchemaEdit(); + return; } - - this.selectItem = table; - await this.showSchema(); } - async deleteTable(table: EditableTable) { - if (table.added) { - const index = this.tables.indexOf(table); - this.tables.splice(index, 1); - // TODO: select other table? - } else { - table.deleted = !table.deleted; - this.selectItem = table; - } + validateTableName = (value: string, state: ValidationState) => { + if (value === undefined) return 'Name cannot be undefined'; + if (emptyString(value)) return 'Name cannot be empty'; + if (value === state.fields.find((field) => field.name === 'name')?.initial) return true; + return !emptyString(value); + }; - this.clear(); - await this.showSchema(); - } + validateColumnName = (value: string) => { + if (value === undefined) return 'Name cannot be undefined'; + if (emptyString(value)) return 'Name cannot be empty'; + return true; + }; + validateColumnNullable = (value: string) => { + if (parseBoolean(value) === undefined) return 'Invalid value. Nullable field must be a boolean'; + return true; + }; + validateColumnUnique = (value: string) => { + if (parseBoolean(value) === undefined) return 'Invalid value. Unique field must be a boolean'; + return true; + }; +} - async deleteColumn(column: EditableColumn, table: EditableTable) { - if (column.added) { - const index = table.columns.indexOf(column); - table.columns.splice(index, 1); - // TODO: select other column? - this.selectItem = table; - } else { - column.deleted = !column.deleted; - this.selectItem = column; - } +const editTableDisabled = (name: string, tableDeletions: DeleteTablePayload[]) => { + return tableDeletions.some(({ name: tableName }) => tableName === name); +}; - this.clear(); - await this.showSchema(); - } +/** Necessary because disabling prevents the user from "undeleting" a column */ +const editColumnDisabled = (column: EditColumnPayload['column'], columnDeletions: DeleteColumnPayload) => { + return columnDeletions[column.tableName]?.includes(column.originalName); +}; - clear() { - process.stdout.write('\x1b[2J'); - process.stdout.write('\x1b[0f'); - } +const validateMigration = (migration: object) => { + return PgRollMigrationDefinition.safeParse(migration); +}; - async migrate() { - this.clear(); +const emptyString = (value: string) => { + return value === ''; +}; - if (!this.branchDetails) this.error('Branch details are not available'); +const createSpace = (): SelectChoice => { + return { name: { type: 'space' }, message: ' ', role: 'heading' }; +}; - const prompt = new Confirm({ - name: 'question', - message: `Are you sure you want to run the migration? ${this.getOverview()}` - }); +export const editsToMigrations = (command: EditSchema) => { + // Duplicating here because if we remove items from class state they dont show on UI + // TODO better way to deep copy? If not surround with try catch - try { - const answer = await prompt.run(); - if (!answer) { - await this.showSchema(); - return; + let localTableAdditions: (AddTablePayload['table'] & { columns?: AddColumnPayload['column'][] })[] = JSON.parse( + JSON.stringify(command.tableAdditions) + ); + let localTableEdits: EditTablePayload['table'][] = JSON.parse(JSON.stringify(command.tableEdits)); + let localTableDeletions: DeleteTablePayload[] = JSON.parse(JSON.stringify(command.tableDeletions)); + + const localColumnAdditions: ColumnAdditions = JSON.parse(JSON.stringify(command.columnAdditions)); + const localColumnEdits: ColumnEdits = JSON.parse(JSON.stringify(command.columnEdits)); + const localColumnDeletions: DeleteColumnPayload = JSON.parse(JSON.stringify(command.columnDeletions)); + + const isTableDeleted = (name: string) => { + return localTableDeletions.find(({ name: tableName }) => tableName === name); + }; + + // Remove column edits, additions and deletions for tables that are deleted + for (const tableName of Object.keys({ + ...localColumnAdditions, + ...localColumnEdits, + ...localColumnDeletions + })) { + if (isTableDeleted(tableName)) { + delete localColumnAdditions[tableName]; + delete localColumnEdits[tableName]; + delete localColumnDeletions[tableName]; + } + } + + // If column was deleted then remove edits, and additions and deletions if new + for (const [tableName, columns] of Object.entries(localColumnDeletions)) { + for (const columnName of columns) { + const columnWasEdited = localColumnEdits[tableName]?.[columnName]; + if (columnWasEdited) { + // Remove the edit + delete localColumnEdits[tableName][columnName]; + } + const columnWasAdded = localColumnAdditions[tableName]?.[columnName]; + if (columnWasAdded) { + // Remove deletions + localColumnDeletions[tableName] = localColumnDeletions[tableName].filter((col) => col !== columnName); + // Remove the addition + delete localColumnAdditions[tableName][columnName]; } - } catch (err) { - if (err) throw err; - // User cancelled - await this.showSchema(); - return; } + } - const workspace = this.workspace; - const region = this.region; - const database = this.database; + // Remove table edits, additions and deletions for tables that are newly added and also deleted + localTableAdditions = localTableAdditions.filter(({ name }) => !isTableDeleted(name)); + localTableEdits = localTableEdits.filter(({ name }) => !isTableDeleted(name)); + localTableDeletions = localTableDeletions.filter( + ({ name }) => !command.tableAdditions.find((addition) => addition.name === name) + ); + + const editsToNewTable = localTableEdits.filter(({ name }) => + localTableAdditions.find((addition) => addition.name === name) + ); + localTableEdits = localTableEdits.filter(({ name }) => !editsToNewTable.find((edit) => edit.name === name)); + localTableAdditions = localTableAdditions.map((addition) => { + const edit = editsToNewTable.find(({ name }) => name === addition.name); + return edit + ? { + name: edit.newName + } + : addition; + }); + + // Bundle edit columns into new columns + for (const [tableName, columns] of Object.entries(localColumnEdits)) { + for (const [columnName, column] of Object.entries(columns)) { + const columnIsNew = localColumnAdditions[tableName]?.[columnName]; + if (columnIsNew) { + // Add to column additions + localColumnAdditions[tableName][columnName] = { + ...column, + name: column.name, + unique: column.unique ?? false, + nullable: column.nullable ?? true + }; + // Delete column from edits + delete localColumnEdits[tableName][columnName]; + if (Object.keys(localColumnEdits[tableName]).length === 0) { + delete localColumnEdits[tableName]; + } + } + } + } - const xata = await this.getXataClient(); - const branch = this.branchDetails.branchName; + // Bundle new columns into new tables + for (const [tableName, columns] of Object.entries(localColumnAdditions)) { + const tableIsNew = localTableAdditions.find((addition) => addition.name === tableName); + if (tableIsNew) { + for (const [columnName, column] of Object.entries(columns)) { + const localTableAddition = localTableAdditions.find((addition) => addition.name === tableName); + if (localTableAddition) { + if (!localTableAddition?.columns) localTableAddition.columns = []; + // Add to table additions + localTableAddition?.columns.push(column); + } + // Delete from column additions + delete localColumnAdditions[tableName][columnName]; + } + delete localColumnAdditions[tableName]; + } + } + + const columnDeletions: { drop_column: OpDropColumn }[] = Object.entries(localColumnDeletions) + .map((entry) => { + return entry[1].map((e) => { + return { + drop_column: { + column: e, + table: entry[0] + } + }; + }); + }) + .flat(); - const edits: Schemas.SchemaEditScript = { - operations: [] + const tableDeletions: { drop_table: OpDropTable }[] = localTableDeletions.map(({ name }) => { + return { + drop_table: { + name: name + } }; + }); - // Create tables, update tables, delete columns and update columns - for (const table of this.tables) { - if (table.added) { - this.info(`Creating table ${table.name}`); - edits.operations.push({ - addTable: { - table: table.name - } - }); - // await xata.tables.createTable({ workspace, region, database, branch, table: table.name }); - } else if (table.initialName) { - this.info(`Renaming table ${table.initialName} to ${table.name}`); - edits.operations.push({ - renameTable: { - newName: table.name, - oldName: table.initialName + const columnAdditions: { add_column: OpAddColumn }[] = []; + for (const [_, columns] of Object.entries(localColumnAdditions)) { + columnAdditions.push( + ...formatColumnDataToPgroll(Object.values(columns)).map(({ column, tableName, up }) => { + return { + add_column: { + up, + column, + table: tableName } - }); + }; + }) + ); + } + + const tableAdditions: { create_table: OpCreateTable }[] = localTableAdditions.map(({ name, columns }) => { + return { + create_table: { + name: name, + columns: formatColumnDataToPgroll(columns ?? []).map(({ column }) => column) } + }; + }); - for (const column of table.columns) { - const linkedTable = this.tables.find((t) => (t.initialName || t.name) === column.link?.table); - if (column.deleted || linkedTable?.deleted) { - this.info(`Deleting column ${table.name}.${column.name}`); - edits.operations.push({ - removeColumn: { - table: table.name, - column: column.name - } - }); - } else if (column.initialName) { - this.info(`Renaming column ${table.name}.${column.initialName} to ${table.name}.${column.name}`); - edits.operations.push({ - renameColumn: { - table: table.name, - newName: column.name, - oldName: column.initialName - } - }); - } + const tableEdits: { rename_table: OpRenameTable }[] = localTableEdits.map(({ name, newName }) => { + return { + rename_table: { + from: name, + to: newName } - } + }; + }); + + const columnEdits: ({ alter_column: OpAlterColumn } | { drop_constraint: OpDropConstraint })[] = []; + for (const [_, columns] of Object.entries(localColumnEdits)) { + for (const data of Object.values(columns)) { + const { name, nullable, unique, originalName } = data; + formatColumnDataToPgroll([data]).map(({ tableName }) => { + const originalField = command.branchDetails?.schema.tables + .find((table) => table.name === tableName) + ?.columns.find((col) => col.name === originalName); + if (!originalField) { + throw new Error(`Could not find original field ${originalName} in table ${tableName}`); + } - // Delete tables and create columns - for (const table of this.tables) { - if (table.deleted) { - this.info(`Deleting table ${table.name}`); - edits.operations.push({ - removeTable: { - table: table.name + const nameChanged = name !== originalField.name; + const nullableChanged = nullable !== !originalField.notNull; + const uniqueAdded = unique !== originalField.unique && unique === true; + const uniqueRemoved = unique !== originalField.unique && unique === false; + + if (uniqueRemoved) { + const table = command.branchDetails?.schema.tables.find((table) => tableName === table.name); + const uniqueConstraints: { name: string }[] = Object.values((table as any)?.uniqueConstraints ?? {}); + const uniqueConstraintName = uniqueConstraints.find( + (constraint: any) => constraint.columns.length === 1 && constraint.columns[0] === originalField.name + )?.name; + + const maybeDropStatement = + uniqueRemoved && uniqueConstraintName + ? { + drop_constraint: { + table: tableName, + column: originalField.name, + name: uniqueConstraintName, + up: `"${originalField.name}"`, + down: `"${originalField.name}"` + } + } + : undefined; + + if (maybeDropStatement) { + columnEdits.push(maybeDropStatement); } - }); - continue; - } + } - for (const column of table.columns) { - if (table.added || column.added) { - this.info(`Adding column ${table.name}.${column.name}`); - edits.operations.push({ - addColumn: { - table: table.name, - column: { - name: column.name, - type: column.type, - link: column.link, - vector: column.vector, - unique: column.unique, - notNull: column.notNull, - defaultValue: column.defaultValue - } + const uniqueValue = uniqueAdded + ? { + unique: { + name: `${tableName}_${originalField.name}_unique` + }, + up: `"${originalField.name}"`, + down: `"${originalField.name}"` } - }); + : undefined; + + const nullValue = nullableChanged + ? { + up: + nullable === false + ? `(SELECT CASE WHEN "${originalField.name}" IS NULL THEN ${xataColumnTypeToZeroValue( + originalField.type, + originalField.defaultValue + )} ELSE "${originalField.name}" END)` + : `"${originalField.name}"`, + down: + nullable === true + ? `"${originalField.name}"` + : `(SELECT CASE WHEN "${originalField.name}" IS NULL THEN ${xataColumnTypeToZeroValue( + originalField.type, + originalField.defaultValue + )} ELSE "${originalField.name}" END)` + } + : undefined; + + const alterStatement = { + alter_column: { + column: originalField.name, + table: tableName, + name: nameChanged ? name : undefined, + nullable: nullableChanged ? nullable : undefined, + ...uniqueValue, + ...nullValue + } + }; + + if (nullableChanged || nameChanged || uniqueAdded) { + columnEdits.push(alterStatement); } - } + }); } - - await xata.api.migrations.applyBranchSchemaEdit({ - workspace, - region, - database, - branch, - edits - }); - - this.success('Migration completed!'); } -} + + return [...columnDeletions, ...tableDeletions, ...tableAdditions, ...columnAdditions, ...columnEdits, ...tableEdits]; +}; function parseBoolean(value?: string) { if (!value) return undefined; const val = value.toLowerCase(); if (['true', 't', '1', 'y', 'yes'].includes(val)) return true; if (['false', 'f', '0', 'n', 'no'].includes(val)) return false; - return null; } -function validateOptionalBoolean(value?: string) { - const bool = parseBoolean(value); - if (bool === null) { - return 'Please enter a boolean value (e.g. yes, no, true, false) or leave it empty'; - } - return true; -} +const formatSchemaColumnToColumnData = ({ + column, + tableName +}: { + column: Schemas.Column & { originalName: string }; + tableName: string; +}): EditColumnPayload['column'] => { + return { + name: column.name, + unique: column.unique ?? false, + type: column.type, + nullable: column.notNull === true ? false : true, + tableName: tableName, + originalName: column.originalName, + defaultValue: column.defaultValue ?? undefined, + vector: column.vector ? { dimension: column.vector.dimension } : undefined, + link: column.type === 'link' && column.link?.table ? { table: column.link.table } : undefined, + file: column.type === 'file' ? { defaultPublicAccess: column.file?.defaultPublicAccess ?? false } : undefined, + 'file[]': + column.type === 'file[]' ? { defaultPublicAccess: column['file[]']?.defaultPublicAccess ?? false } : undefined + }; +}; -function validateUnique(uniqueValue: string | undefined, state: ColumnEditState) { - const isUnique = parseBoolean(uniqueValue); - if (isUnique && state.values.type && uniqueUnsupportedTypes.includes(state.values.type)) { - return `Column type \`${state.values.type}\` does not support \`unique: true\``; - } - if (isUnique && parseBoolean(state.values.notNull)) { - return 'Column cannot be both `unique: true` and `notNull: true`'; - } - if (isUnique && state.values.defaultValue) { - return 'Column cannot be both `unique: true` and have a `defaultValue` set'; - } - return true; -} +const formatColumnDataToPgroll = ( + columns: AddColumnPayload['column'][] +): { column: OpAddColumn['column']; tableName: string; up?: string }[] => { + return columns.map((column) => ({ + tableName: column.tableName, + up: requiresUpArgument(column.nullable === false, column.defaultValue) + ? xataColumnTypeToZeroValue(column.type as any, column.defaultValue) + : undefined, + column: { + name: column.name, + type: xataColumnTypeToPgRoll(column.type as any), + references: + column.type === 'link' + ? generateLinkReference({ column: column.name, table: column.link?.table ?? '' }) + : undefined, + default: + column.defaultValue !== null && column.defaultValue !== undefined ? `'${column.defaultValue}'` : undefined, + nullable: parseBoolean(String(column.nullable)) ?? true, + unique: parseBoolean(String(column.unique)) ?? false, + check: xataColumnTypeToPgRollConstraint(column as any, column.tableName), + comment: xataColumnTypeToPgRollComment(column as any) + } + })); +}; -function validateNotNull(notNullValue: string | undefined, state: ColumnEditState) { - const isNotNull = parseBoolean(notNullValue); - if (isNotNull && state.values.type && notNullUnsupportedTypes.includes(state.values.type)) { - return `Column type \`${state.values.type}\` does not support \`notNull: true\``; - } +export type BranchSchemaFormatted = + | { + schema: { + tables: { + name: string; + uniqueConstraints: Schemas.BranchSchema['tables'][number]['uniqueConstraints']; + checkConstraints: Schemas.BranchSchema['tables'][number]['checkConstraints']; + foreignKeys: Schemas.BranchSchema['tables'][number]['foreignKeys']; + columns: { + name: string; + type: string; + unique: boolean; + notNull: boolean; + defaultValue: any; + comment: string; + }[]; + }[]; + }; + } + | undefined; + +export type ColumnData = { + name: string; + type: string; + unique: boolean; + nullable: boolean; + defaultValue?: string; + vector?: { + dimension: number; + }; + originalName: string; + tableName: string; + link?: { + table: string; + }; + file?: { + defaultPublicAccess: boolean; + }; + 'file[]'?: { + defaultPublicAccess: boolean; + }; +}; - return true; -} +export type AddTablePayload = { + type: 'add-table'; + table: { + name: string; + }; +}; -function parseDefaultValue(type: string, val?: string): string | undefined { - if (val === undefined || defaultValueUnsupportedTypes.includes(type)) { - return undefined; - } - const num = String(val).length > 0 ? +val : undefined; - - if (['text', 'string'].includes(type)) { - return val === '' ? undefined : String(val); - } else if (type === 'int') { - return Number.isSafeInteger(num) && val !== '' ? String(num) : undefined; - } else if (type === 'float') { - return Number.isFinite(num) && val !== '' ? String(num) : undefined; - } else if (type === 'bool') { - const booleanValue = parseBoolean(val); - return !isNil(booleanValue) ? String(booleanValue) : undefined; - } else if (type === 'email') { - if (!isValidEmail(val)) { - return undefined; - } - return val; - } else if (type === 'datetime') { - // Date fields have special values - if (['now'].includes(val)) return val; - - const date = new Date(val); - return isNaN(date.getTime()) ? undefined : date.toISOString(); - } else { - return undefined; - } -} +export type EditTablePayload = { + type: 'edit-table'; + table: { + name: string; + newName: string; + }; +}; + +export type DeleteTablePayload = { + name: string; +}; + +export type AddColumnPayload = { + type: 'add-column'; + tableName: string; + column: ColumnData; +}; + +export type EditColumnPayload = { + type: 'edit-column'; + column: ColumnData; +}; + +export type DeleteColumnPayload = { [tableName: string]: string[] }; + +export type FormatPayload = { + type: 'space' | 'migrate' | 'schema'; +}; + +export type SelectChoice = { + name: FormatPayload | AddTablePayload | EditTablePayload | AddColumnPayload | EditColumnPayload; + message: string; + role?: string; + choices?: SelectChoice[]; + disabled?: boolean; + hint?: string; +}; + +export type ValidationState = { + values: { name: string }; + items: { name: string; input: string }[]; + fields: { name: string; initial: string }[]; +}; + +export type ColumnAdditions = { [tableName: string]: { [columnName: string]: AddColumnPayload['column'] } }; + +export type ColumnEdits = { [tableName: string]: { [columnName: string]: AddColumnPayload['column'] } }; diff --git a/cli/src/commands/schema/upload.ts b/cli/src/commands/schema/upload.ts index ca9d016f2..e91e83487 100644 --- a/cli/src/commands/schema/upload.ts +++ b/cli/src/commands/schema/upload.ts @@ -49,11 +49,8 @@ export default class UploadSchema extends BaseCommand { } const { edits } = await xata.api.migrations.compareBranchWithUserSchema({ - workspace, - region, - database, - branch, - schema + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + body: { schema } }); if (edits.operations.length === 0) { @@ -72,6 +69,9 @@ export default class UploadSchema extends BaseCommand { }); if (!confirm) return this.exit(1); - await xata.api.migrations.applyBranchSchemaEdit({ workspace, region, database, branch, edits }); + await xata.api.migrations.applyBranchSchemaEdit({ + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, + body: { edits } + }); } } diff --git a/cli/src/commands/workspace/create.ts b/cli/src/commands/workspace/create.ts index 0c7bf3541..de24b4960 100644 --- a/cli/src/commands/workspace/create.ts +++ b/cli/src/commands/workspace/create.ts @@ -26,7 +26,7 @@ export default class WorkspaceCreate extends BaseCommand const xata = await this.getXataClient(); - const result = await xata.api.workspaces.createWorkspace({ data: { name: workspace } }); + const result = await xata.api.workspaces.createWorkspace({ body: { name: workspace } }); if (this.jsonEnabled()) return result; diff --git a/cli/src/commands/workspace/delete.ts b/cli/src/commands/workspace/delete.ts index 02763e73a..719f2bd9b 100644 --- a/cli/src/commands/workspace/delete.ts +++ b/cli/src/commands/workspace/delete.ts @@ -35,7 +35,7 @@ export default class WorkspaceDelete extends BaseCommand if (!confirm) return this.exit(1); if (confirm !== workspace) return this.error('The workspace name did not match'); - await xata.api.workspaces.deleteWorkspace({ workspace }); + await xata.api.workspaces.deleteWorkspace({ pathParams: { workspaceId: workspace } }); if (this.jsonEnabled()) return {}; diff --git a/cli/src/migrations/files.ts b/cli/src/migrations/files.ts index e6149bb47..fccfd6d4d 100644 --- a/cli/src/migrations/files.ts +++ b/cli/src/migrations/files.ts @@ -97,7 +97,7 @@ export async function removeLocalMigrations() { } } -export function commitToMigrationFile(logs: Schemas.Commit[] | Schemas.MigrationHistoryItem[]): LocalMigrationFile[] { +export function commitToMigrationFile(logs: (Schemas.Commit | Schemas.MigrationHistoryItem)[]): LocalMigrationFile[] { // Schema history comes in reverse order, so we need to reverse it return logs.reverse().map((log) => isMigrationPgRollFormat(log) diff --git a/cli/src/migrations/pgroll.ts b/cli/src/migrations/pgroll.ts index 591a5d39e..97f6e4b3e 100644 --- a/cli/src/migrations/pgroll.ts +++ b/cli/src/migrations/pgroll.ts @@ -1,9 +1,13 @@ -import { Schemas } from '@xata.io/client'; -import { migrationsDir, readMigrationsDir } from './files.js'; +import { Schemas, XataApiClient } from '@xata.io/client'; +import { Column } from '@xata.io/codegen'; import path from 'path'; -import { safeJSONParse, safeReadFile } from '../utils/files.js'; -import { migrationFilePgroll, MigrationFilePgroll } from './schema.js'; +import z from 'zod'; import { XataClient } from '../base.js'; +import { safeJSONParse, safeReadFile } from '../utils/files.js'; +import { migrationsDir, readMigrationsDir } from './files.js'; +import { MigrationFilePgroll, migrationFilePgroll } from './schema.js'; +import { OpRawSQL, OpRenameConstraint, PgRollOperation } from '@xata.io/pgroll'; +import { BranchSchemaFormatted } from '../commands/schema/edit.js'; export const isBranchPgRollEnabled = (details: Schemas.DBBranch) => { // @ts-expect-error TODO: Fix this when api is finalized @@ -47,21 +51,45 @@ const getPgRollLink = (table: any, column: any) => { return null; }; -function pgRollToXataColumnType(type: string): string { +export const xataStringColumns = ['email', 'text', 'string'] as const; + +const XataStringColumn = z.object({ + ['xata.type']: z.enum(xataStringColumns) +}); + +export type XataStringColumnType = z.infer; + +const narrowStringType = (comment?: string): Column['type'] => { + if (!comment) return 'text'; + const result = XataStringColumn.safeParse(JSON.parse(comment)); + return result.success ? result.data['xata.type'] : 'text'; +}; + +function pgRollToXataColumnType(type: string, comment?: string): string { switch (type) { case 'boolean': + case 'bool': return 'bool'; case 'bigint': + case 'int8': case 'integer': + case 'int': + case 'int4': + case 'smallint': return 'int'; case 'double precision': + case 'float8': + case 'real': return 'float'; case 'text': - return 'text'; + case 'varchar': + case 'character varying': + return narrowStringType(comment); case 'timestamptz': return 'datetime'; case 'text[]': return 'multiple'; + case 'json': case 'jsonb': return 'json'; case 'xata_file': @@ -70,19 +98,26 @@ function pgRollToXataColumnType(type: string): string { return 'file[]'; case 'real[]': return 'vector'; - default: - return type; } + + if (type.startsWith('character(') || type.startsWith('varchar(')) return 'string'; + if (type.startsWith('numeric(')) return 'float'; + + return type; } export async function getBranchDetailsWithPgRoll( xata: XataClient, { workspace, region, database, branch }: { workspace: string; region: string; database: string; branch: string } ): Promise { - const details = await xata.api.branches.getBranchDetails({ workspace, region, database, branch }); + const details = await xata.api.branch.getBranchDetails({ + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` } + }); if (isBranchPgRollEnabled(details)) { - const pgroll = await xata.api.migrations.getSchema({ workspace, region, database, branch }); + const pgroll = await xata.api.migrations.getSchema({ + pathParams: { workspace, region, dbBranchName: `${database}:${branch}` } + }); return { ...details, @@ -96,11 +131,15 @@ export async function getBranchDetailsWithPgRoll( schema: { tables: Object.entries(pgroll.schema.tables ?? []).map(([name, table]: any) => ({ name, + checkConstraints: table.checkConstraints, + foreignKeys: table.foreignKeys, + primaryKey: table.primaryKey, + uniqueConstraints: table.uniqueConstraints, columns: Object.values(table.columns ?? {}) .filter((column: any) => !['_id', '_createdat', '_updatedat', '_version'].includes(column.name)) .map((column: any) => ({ name: column.name, - type: getPgRollLink(table, column) ? 'link' : pgRollToXataColumnType(column.type), + type: getPgRollLink(table, column) ? 'link' : pgRollToXataColumnType(column.type, column.comment), link: getPgRollLink(table, column) ? { table: getPgRollLink(table, column).referencedTable } : undefined, file: pgRollToXataColumnType(column.type) === 'file' || pgRollToXataColumnType(column.type) === 'file[]' @@ -108,7 +147,8 @@ export async function getBranchDetailsWithPgRoll( : undefined, notNull: column.nullable === false, unique: column.unique === true, - defaultValue: column.default + defaultValue: column.default, + comment: column.comment })) })) } as any @@ -117,3 +157,362 @@ export async function getBranchDetailsWithPgRoll( return details; } + +export const isColumnTypeUnsupported = (type: string) => { + switch (type) { + case 'bool': + case 'int': + case 'float': + case 'datetime': + case 'multiple': + case 'json': + case 'file': + case 'file[]': + case 'text': + case 'link': + case 'string': + case 'email': + case 'vector': + return false; + default: + return true; + } +}; + +export function xataColumnTypeToPgRoll(type: Column['type']): string { + if (isColumnTypeUnsupported(type)) return type; + switch (type) { + case 'bool': + return 'boolean'; + case 'int': + return 'bigint'; + case 'float': + return 'double precision'; + case 'datetime': + return 'timestamptz'; + case 'multiple': + return 'text[]'; + case 'json': + return 'jsonb'; + case 'file': + return 'xata.xata_file'; + case 'file[]': + return 'xata.xata_file_array'; + case 'text': + case 'string': + case 'email': + case 'link': + return 'text'; + case 'vector': + return 'real[]'; + default: + return 'text'; + } +} + +export const exhaustiveCheck = (x: never): never => { + throw new Error(`Unhandled discriminated union member: ${x}`); +}; + +export const generateLinkReference = ({ + column, + table, + onDelete: on_delete = 'SET NULL' +}: { + column: string; + table: string; + onDelete?: string; +}) => { + return { + name: `${column}_link`, + table, + column: 'xata_id', + on_delete + }; +}; + +export const xataColumnTypeToPgRollConstraintName = ( + tableName: string, + columnName: string, + columnType: Column['type'] +) => { + return `${tableName}_xata_${columnType}_length_${columnName}`; +}; + +export const xataColumnTypeToPgRollConstraint = (column: Column, table: string) => { + const getConstraint = () => { + if (isColumnTypeUnsupported(column.type)) return undefined; + switch (column.type) { + case 'vector': + return `ARRAY_LENGTH("${column.name}", 1) = ${column.vector?.dimension}`; + case 'string': + case 'email': + return `LENGTH("${column.name}") <= 2048`; + case 'text': + return `OCTET_LENGTH("${column.name}") <= 204800`; + case 'multiple': + return `OCTET_LENGTH(ARRAY_TO_STRING("${column.name}", '')) < 65536`; + case 'link': + case 'bool': + case 'datetime': + case 'file': + case 'file[]': + case 'float': + case 'int': + case 'json': + return undefined; + default: + return undefined; + } + }; + + const constraint = getConstraint(); + return constraint + ? { + name: xataColumnTypeToPgRollConstraintName(table, column.name, column.type), + constraint + } + : undefined; +}; + +export const xataColumnTypeToPgRollComment = (column: Column) => { + const getType = () => { + switch (column.type) { + case 'vector': + return { 'xata.search.dimension': column.vector?.dimension }; + case 'link': + return { 'xata.link': column.link?.table }; + case 'string': + case 'text': + case 'email': + return { 'xata.type': column.type }; + case 'file': + return { 'xata.file.dpa': column.file?.defaultPublicAccess ?? false }; + case 'file[]': + return { 'xata.file.dpa': column['file[]']?.defaultPublicAccess ?? false }; + case 'float': + case 'int': + case 'json': + case 'multiple': + case 'bool': + case 'datetime': + return undefined; + default: + return 'text'; + } + }; + + const result = getType(); + return result !== undefined ? JSON.stringify(result) : undefined; +}; + +export const requiresUpArgument = (notNull: Column['notNull'], defaultValue: unknown) => + notNull && (defaultValue === null || defaultValue === undefined); + +export function xataColumnTypeToZeroValue(type: Column['type'], defaultValue: unknown): string { + if (defaultValue !== undefined && defaultValue !== null) return `${defaultValue}`; + if (isColumnTypeUnsupported(type)) return "''"; + switch (type) { + case 'bool': + return 'false'; + case 'int': + case 'float': + return '0'; + case 'datetime': + return 'now()'; + case 'link': + return 'null'; + case 'email': + case 'text': + case 'string': + return "''"; + case 'vector': + case 'multiple': + case 'json': + case 'file': + case 'file[]': + return "'{}'"; + default: + return "''"; + } +} + +export async function waitForMigrationToFinish( + api: XataApiClient, + workspace: string, + region: string, + database: string, + branch: string, + jobId: string +): Promise { + const { status, error } = await api.migrations.getMigrationJobStatus({ + pathParams: { + workspace: workspace, + region: region, + dbBranchName: `${database}:${branch}`, + jobId + } + }); + if (status === 'failed') { + throw new Error(`Migration failed, ${error}`); + } + + if (status === 'completed') { + return; + } + + await new Promise((resolve) => setTimeout(resolve, 1000)); + return await waitForMigrationToFinish(api, workspace, region, database, branch, jobId); +} + +const getTable = (tableName: string, branchDetails: BranchSchemaFormatted) => { + return branchDetails?.schema.tables.find((table) => table.name === tableName); +}; + +export const updateConstraint = ( + branchDetails: BranchSchemaFormatted, + operation: PgRollOperation +): { rename_constraint: OpRenameConstraint }[] | undefined => { + const migrations: { rename_constraint: OpRenameConstraint }[] = []; + + const getUpdatedConstraintName = (params: { + constraintName: string; + replacement: string; + type: 'table' | 'column'; + }) => { + const { constraintName, replacement, type } = params; + const baseRegex = '_xata_(?:vector|string|text|multiple|email)_length_'; + const regex = + type === 'table' ? new RegExp(`(.*)${baseRegex}(?:.*)`, 'dgm') : new RegExp(`(?:.*)${baseRegex}(.*)`, 'dgm'); + + type RegExpMatchArrayWithIndices = RegExpMatchArray & { indices: Array<[number, number]> }; + + const matches = regex.exec(constraintName) as RegExpMatchArrayWithIndices; + if (!matches) return constraintName; + // e.g. of indices: [ [ 0, 24 ], [ 22, 24 ] + if (matches?.indices?.length !== 2 || matches?.indices[0]?.length !== 2) return constraintName; + const start = matches.indices[1][0]; + const finish = matches.indices[1][1]; + const arr = constraintName.split(''); + arr.splice(start, finish, replacement); + return arr.join(''); + }; + + if ( + 'alter_column' in operation && + operation.alter_column.name && + operation.alter_column.name !== operation.alter_column.column + ) { + const table = getTable(operation.alter_column.table, branchDetails); + if (!table) return undefined; + + const oldColumn = table.columns + .map(({ type, name, comment }) => ({ type, name, comment })) + .find((column) => column.name === operation.alter_column.column); + if (!oldColumn) return undefined; + + const oldColumnType = pgRollToXataColumnType(oldColumn.type, oldColumn.comment); + if (!oldColumnType) return undefined; + + const constraint = Object.values(table.checkConstraints ?? {}).find( + (constraint) => + constraint.name === + xataColumnTypeToPgRollConstraintName(table.name, operation.alter_column.column, oldColumnType as Column['type']) + ); + if (!constraint) return undefined; + + const newConstraintName = getUpdatedConstraintName({ + constraintName: constraint.name, + replacement: operation.alter_column.name, + type: 'column' + }); + if (newConstraintName === constraint.name) return undefined; + + migrations.push({ + rename_constraint: { + table: table.name, + from: constraint.name, + to: newConstraintName + } + }); + } + + if ('rename_table' in operation) { + const table = getTable(operation.rename_table.from, branchDetails); + if (!table) return undefined; + + Object.values(table.checkConstraints ?? {}).forEach((constraint) => { + const newConstraintName = getUpdatedConstraintName({ + constraintName: constraint.name, + replacement: operation.rename_table.to, + type: 'table' + }); + if (newConstraintName === constraint.name) return undefined; + + migrations.push({ + rename_constraint: { + table: operation.rename_table.to, + from: constraint.name, + to: newConstraintName + } + }); + }); + } + + return migrations.length > 0 ? migrations : undefined; +}; + +const isValidXataLink = ({ key }: { key: Schemas.BranchSchema['tables'][number]['foreignKeys'][number] }) => { + return key.referencedColumns.length === 1 && key.referencedColumns.includes('xata_id'); +}; + +export const updateLinkComment = ( + branchDetails: BranchSchemaFormatted, + operation: PgRollOperation +): { sql: OpRawSQL }[] | undefined => { + const migrationSql: string[] = []; + + if ('rename_table' in operation) { + const tablesToUpdate = + branchDetails?.schema.tables.reduce((acc, table) => { + const keys = Object.values(table.foreignKeys); + for (const key of keys) { + if (key.referencedTable === operation.rename_table.from && isValidXataLink({ key })) { + acc.push({ [table.name]: key.columns }); + } + } + return acc; + }, [] as { [tableName: string]: string[] }[]) ?? []; + + for (const key of tablesToUpdate) { + const tableName = Object.keys(key)[0]; + const columns = key[tableName]; + columns.forEach((column) => { + const table = getTable(tableName, branchDetails); + const columnToUpdate = table?.columns.find((col) => col.name === column); + if (tableNameFromLinkComment(columnToUpdate?.comment ?? '')) { + migrationSql.push( + `COMMENT ON COLUMN "${tableName}"."${column}" IS '${JSON.stringify({ + 'xata.link': operation.rename_table.to + })}'` + ); + } + }); + } + } + return migrationSql.length > 0 ? [{ sql: { up: migrationSql.join(';') } }] : undefined; +}; + +const XataLinkColumn = z.object({ + ['xata.link']: z.string() +}); + +export const tableNameFromLinkComment = (comment: string) => { + try { + const obj = JSON.parse(comment); + const result = XataLinkColumn.safeParse(obj); + return result.success ? result.data['xata.link'] : null; + } catch (e) { + return null; + } +}; diff --git a/cli/src/utils/compareSchema.ts b/cli/src/utils/compareSchema.ts new file mode 100644 index 000000000..3bcdcabfa --- /dev/null +++ b/cli/src/utils/compareSchema.ts @@ -0,0 +1,129 @@ +import { PgRollOperation } from '@xata.io/pgroll'; +import { PartialDeep } from 'type-fest'; +import { Schemas } from '@xata.io/client'; +import { generateLinkReference, tableNameFromLinkComment, xataColumnTypeToPgRoll } from '../migrations/pgroll.js'; + +export function compareSchemas( + source: PartialDeep, + target: PartialDeep +): { edits: PgRollOperation[] } { + const edits: PgRollOperation[] = []; + + // Compare tables + const sourceTables = Object.keys(source.tables ?? {}); + const targetTables = Object.keys(target.tables ?? {}); + const newTables = targetTables.filter((table) => !sourceTables.includes(table)); + const deletedTables = sourceTables.filter((table) => !targetTables.includes(table)); + + // Compare columns + for (const table of sourceTables) { + const sourceColumns = Object.keys(source.tables?.[table]?.columns ?? {}); + const targetColumns = Object.keys(target.tables?.[table]?.columns ?? {}); + const newColumns = targetColumns.filter((column) => !sourceColumns.includes(column)); + const deletedColumns = sourceColumns.filter((column) => !targetColumns.includes(column)); + + // Add columns + for (const column of newColumns) { + const props = target.tables?.[table]?.columns?.[column] ?? {}; + edits.push({ + add_column: { + table, + column: { + name: column, + type: xataColumnTypeToPgRoll(props?.type as any), + comment: props?.comment, + nullable: !(props?.nullable === false), + unique: props?.unique, + default: props?.default ?? undefined, + references: + props?.type === 'link' && props?.name + ? generateLinkReference({ + column: props.name, + table: tableNameFromLinkComment(props?.comment ?? '') ?? '' + }) + : undefined + } + } + }); + } + + // Delete columns + for (const column of deletedColumns) { + edits.push({ drop_column: { table, column } }); + } + + // Compare column properties + for (const column of targetColumns) { + const sourceProps = source.tables?.[table]?.columns?.[column] ?? {}; + const targetProps = target.tables?.[table]?.columns?.[column] ?? {}; + + if (sourceProps.type !== targetProps.type) { + edits.push({ + alter_column: { + table, + column, + type: targetProps.type, + references: + targetProps?.type === 'link' && targetProps?.name + ? generateLinkReference({ + column: targetProps.name, + table: tableNameFromLinkComment(targetProps?.comment ?? '') ?? '' + }) + : undefined + } + }); + } + + if (sourceProps.nullable !== targetProps.nullable) { + edits.push({ alter_column: { table, column, nullable: targetProps.nullable } }); + } + + if (sourceProps.unique !== targetProps.unique) { + edits.push({ + alter_column: { + table, + column, + unique: { + name: `${table}_${column}_unique` + } + } + }); + } + } + } + + // Delete tables + for (const table of deletedTables) { + edits.push({ drop_table: { name: table } }); + } + + // Add new tables + for (const table of newTables) { + const props = target.tables?.[table] ?? {}; + edits.push({ + create_table: { + name: table, + comment: props.comment, + columns: Object.entries(props.columns ?? {}).map(([name, column]) => { + return { + name, + type: xataColumnTypeToPgRoll(column?.type as any), + comment: column?.comment, + nullable: !(column?.nullable === false), + unique: column?.unique, + default: column?.default ?? undefined, + references: + column?.type === 'link' && column?.name + ? generateLinkReference({ + column: column?.name, + table: tableNameFromLinkComment(column?.comment ?? '') ?? '' + }) + : undefined + }; + }) + } + }); + } + + return { edits }; +} diff --git a/packages/client/src/api/client.test.ts b/packages/client/src/api/client.test.ts new file mode 100644 index 000000000..b6ac59138 --- /dev/null +++ b/packages/client/src/api/client.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, test } from 'vitest'; +import { XataApiClient } from './client'; +import { operationsByTag } from './components'; + +const xata = new XataApiClient({ apiKey: 'fake-api-key' }); + +describe('API Proxy types', () => { + test('returns functions for all defined namespace operations', () => { + for (const namespace of Object.keys(operationsByTag)) { + const operationsInNamespace = operationsByTag[namespace as keyof typeof operationsByTag]; + for (const operation of Object.keys(operationsInNamespace)) { + expect(operationsInNamespace[operation as keyof typeof operationsInNamespace]).toBeInstanceOf(Function); + } + } + }); + + test('returns undefined for undefined namespaces', () => { + // @ts-expect-error Not a valid namespace + expect(xata.undefinedNamespace).toBeUndefined(); + }); + + test('returns undefined for undefined namespace operations', () => { + // @ts-expect-error Not a valid operation + expect(xata.authentication.undefinedOperation).toBeUndefined(); + }); +}); diff --git a/packages/client/src/api/client.ts b/packages/client/src/api/client.ts index cd7ddc9e6..67eb2c989 100644 --- a/packages/client/src/api/client.ts +++ b/packages/client/src/api/client.ts @@ -1,14 +1,11 @@ import { defaultTrace, TraceFunction } from '../schema/tracing'; import { getAPIKey } from '../util/environment'; import { FetchImpl, getFetchImplementation } from '../util/fetch'; +import { RequiredKeys } from '../util/types'; import { generateUUID } from '../util/uuid'; -import type * as Components from './components'; -import type * as Types from './components'; import { operationsByTag } from './components'; import type { FetcherExtraProps } from './fetcher'; import { getHostUrl, HostProvider } from './providers'; -import type * as Responses from './responses'; -import type * as Schemas from './schemas'; export type ApiExtraProps = Omit; @@ -21,1961 +18,72 @@ export interface XataApiClientOptions { xataAgentExtra?: Record; } -export class XataApiClient { - #extraProps: ApiExtraProps; - #namespaces: Partial<{ - user: UserApi; - authentication: AuthenticationApi; - workspaces: WorkspaceApi; - invites: InvitesApi; - database: DatabaseApi; - branches: BranchApi; - migrations: MigrationsApi; - migrationRequests: MigrationRequestsApi; - tables: TableApi; - records: RecordsApi; - files: FilesApi; - searchAndFilter: SearchAndFilterApi; - }> = {}; - - constructor(options: XataApiClientOptions = {}) { - const provider = options.host ?? 'production'; - const apiKey = options.apiKey ?? getAPIKey(); - const trace = options.trace ?? defaultTrace; - const clientID = generateUUID(); - - if (!apiKey) { - throw new Error('Could not resolve a valid apiKey'); - } - - this.#extraProps = { - apiUrl: getHostUrl(provider, 'main'), - workspacesApiUrl: getHostUrl(provider, 'workspaces'), - fetch: getFetchImplementation(options.fetch), - apiKey, - trace, - clientName: options.clientName, - xataAgentExtra: options.xataAgentExtra, - clientID - }; - } - - public get user() { - if (!this.#namespaces.user) this.#namespaces.user = new UserApi(this.#extraProps); - return this.#namespaces.user; - } - - public get authentication() { - if (!this.#namespaces.authentication) this.#namespaces.authentication = new AuthenticationApi(this.#extraProps); - return this.#namespaces.authentication; - } - - public get workspaces() { - if (!this.#namespaces.workspaces) this.#namespaces.workspaces = new WorkspaceApi(this.#extraProps); - return this.#namespaces.workspaces; - } - - public get invites() { - if (!this.#namespaces.invites) this.#namespaces.invites = new InvitesApi(this.#extraProps); - return this.#namespaces.invites; - } - - public get database() { - if (!this.#namespaces.database) this.#namespaces.database = new DatabaseApi(this.#extraProps); - return this.#namespaces.database; - } - - public get branches() { - if (!this.#namespaces.branches) this.#namespaces.branches = new BranchApi(this.#extraProps); - return this.#namespaces.branches; - } - - public get migrations() { - if (!this.#namespaces.migrations) this.#namespaces.migrations = new MigrationsApi(this.#extraProps); - return this.#namespaces.migrations; - } - - public get migrationRequests() { - if (!this.#namespaces.migrationRequests) - this.#namespaces.migrationRequests = new MigrationRequestsApi(this.#extraProps); - return this.#namespaces.migrationRequests; - } - - public get tables() { - if (!this.#namespaces.tables) this.#namespaces.tables = new TableApi(this.#extraProps); - return this.#namespaces.tables; - } - - public get records() { - if (!this.#namespaces.records) this.#namespaces.records = new RecordsApi(this.#extraProps); - return this.#namespaces.records; - } - - public get files() { - if (!this.#namespaces.files) this.#namespaces.files = new FilesApi(this.#extraProps); - return this.#namespaces.files; - } - - public get searchAndFilter() { - if (!this.#namespaces.searchAndFilter) this.#namespaces.searchAndFilter = new SearchAndFilterApi(this.#extraProps); - return this.#namespaces.searchAndFilter; - } -} - -class UserApi { - constructor(private extraProps: ApiExtraProps) {} - - public getUser(): Promise { - return operationsByTag.users.getUser({ ...this.extraProps }); - } - - public updateUser({ user }: { user: Schemas.User }): Promise { - return operationsByTag.users.updateUser({ body: user, ...this.extraProps }); - } - - public deleteUser(): Promise { - return operationsByTag.users.deleteUser({ ...this.extraProps }); - } -} - -class AuthenticationApi { - constructor(private extraProps: ApiExtraProps) {} - - public getUserAPIKeys(): Promise { - return operationsByTag.authentication.getUserAPIKeys({ ...this.extraProps }); - } - - public createUserAPIKey({ name }: { name: Schemas.APIKeyName }): Promise { - return operationsByTag.authentication.createUserAPIKey({ - pathParams: { keyName: name }, - ...this.extraProps - }); - } - - public deleteUserAPIKey({ name }: { name: Schemas.APIKeyName }): Promise { - return operationsByTag.authentication.deleteUserAPIKey({ - pathParams: { keyName: name }, - ...this.extraProps - }); - } -} - -class WorkspaceApi { - constructor(private extraProps: ApiExtraProps) {} - - public getWorkspacesList(): Promise { - return operationsByTag.workspaces.getWorkspacesList({ ...this.extraProps }); - } - - public createWorkspace({ data }: { data: Schemas.WorkspaceMeta }): Promise { - return operationsByTag.workspaces.createWorkspace({ - body: data, - ...this.extraProps - }); - } - - public getWorkspace({ workspace }: { workspace: Schemas.WorkspaceID }): Promise { - return operationsByTag.workspaces.getWorkspace({ - pathParams: { workspaceId: workspace }, - ...this.extraProps - }); - } - - public updateWorkspace({ - workspace, - update - }: { - workspace: Schemas.WorkspaceID; - update: Schemas.WorkspaceMeta; - }): Promise { - return operationsByTag.workspaces.updateWorkspace({ - pathParams: { workspaceId: workspace }, - body: update, - ...this.extraProps - }); - } - - public deleteWorkspace({ workspace }: { workspace: Schemas.WorkspaceID }): Promise { - return operationsByTag.workspaces.deleteWorkspace({ - pathParams: { workspaceId: workspace }, - ...this.extraProps - }); - } - - public getWorkspaceMembersList({ workspace }: { workspace: Schemas.WorkspaceID }): Promise { - return operationsByTag.workspaces.getWorkspaceMembersList({ - pathParams: { workspaceId: workspace }, - ...this.extraProps - }); - } - - public updateWorkspaceMemberRole({ - workspace, - user, - role - }: { - workspace: Schemas.WorkspaceID; - user: Schemas.UserID; - role: Schemas.Role; - }): Promise { - return operationsByTag.workspaces.updateWorkspaceMemberRole({ - pathParams: { workspaceId: workspace, userId: user }, - body: { role }, - ...this.extraProps - }); - } - - public removeWorkspaceMember({ - workspace, - user - }: { - workspace: Schemas.WorkspaceID; - user: Schemas.UserID; - }): Promise { - return operationsByTag.workspaces.removeWorkspaceMember({ - pathParams: { workspaceId: workspace, userId: user }, - ...this.extraProps - }); - } -} - -class InvitesApi { - constructor(private extraProps: ApiExtraProps) {} - - public inviteWorkspaceMember({ - workspace, - email, - role - }: { - workspace: Schemas.WorkspaceID; - email: string; - role: Schemas.Role; - }): Promise { - return operationsByTag.invites.inviteWorkspaceMember({ - pathParams: { workspaceId: workspace }, - body: { email, role }, - ...this.extraProps - }); - } - - public updateWorkspaceMemberInvite({ - workspace, - invite, - role - }: { - workspace: Schemas.WorkspaceID; - invite: Schemas.InviteID; - role: Schemas.Role; - }): Promise { - return operationsByTag.invites.updateWorkspaceMemberInvite({ - pathParams: { workspaceId: workspace, inviteId: invite }, - body: { role }, - ...this.extraProps - }); - } - - public cancelWorkspaceMemberInvite({ - workspace, - invite - }: { - workspace: Schemas.WorkspaceID; - invite: Schemas.InviteID; - }): Promise { - return operationsByTag.invites.cancelWorkspaceMemberInvite({ - pathParams: { workspaceId: workspace, inviteId: invite }, - ...this.extraProps - }); - } - - public acceptWorkspaceMemberInvite({ - workspace, - key - }: { - workspace: Schemas.WorkspaceID; - key: Schemas.InviteKey; - }): Promise { - return operationsByTag.invites.acceptWorkspaceMemberInvite({ - pathParams: { workspaceId: workspace, inviteKey: key }, - ...this.extraProps - }); - } - - public resendWorkspaceMemberInvite({ - workspace, - invite - }: { - workspace: Schemas.WorkspaceID; - invite: Schemas.InviteID; - }): Promise { - return operationsByTag.invites.resendWorkspaceMemberInvite({ - pathParams: { workspaceId: workspace, inviteId: invite }, - ...this.extraProps - }); - } -} - -class BranchApi { - constructor(private extraProps: ApiExtraProps) {} - - public getBranchList({ - workspace, - region, - database - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - }): Promise { - return operationsByTag.branch.getBranchList({ - pathParams: { workspace, region, dbName: database }, - ...this.extraProps - }); - } - - public getBranchDetails({ - workspace, - region, - database, - branch - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - }): Promise { - return operationsByTag.branch.getBranchDetails({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - ...this.extraProps - }); - } - - public createBranch({ - workspace, - region, - database, - branch, - from, - metadata - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - from?: string; - metadata?: Schemas.BranchMetadata; - }): Promise { - return operationsByTag.branch.createBranch({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: { from, metadata }, - ...this.extraProps - }); - } - - public deleteBranch({ - workspace, - region, - database, - branch - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - }): Promise { - return operationsByTag.branch.deleteBranch({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - ...this.extraProps - }); - } - - public copyBranch({ - workspace, - region, - database, - branch, - destinationBranch, - limit - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - destinationBranch: Schemas.BranchName; - limit?: number; - }): Promise { - return operationsByTag.branch.copyBranch({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: { destinationBranch, limit }, - ...this.extraProps - }); - } - - public updateBranchMetadata({ - workspace, - region, - database, - branch, - metadata - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - metadata: Schemas.BranchMetadata; - }): Promise { - return operationsByTag.branch.updateBranchMetadata({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: metadata, - ...this.extraProps - }); - } - - public getBranchMetadata({ - workspace, - region, - database, - branch - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - }): Promise { - return operationsByTag.branch.getBranchMetadata({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - ...this.extraProps - }); - } - - public getBranchStats({ - workspace, - region, - database, - branch - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - }): Promise { - return operationsByTag.branch.getBranchStats({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - ...this.extraProps - }); - } - - public getGitBranchesMapping({ - workspace, - region, - database - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - }): Promise { - return operationsByTag.branch.getGitBranchesMapping({ - pathParams: { workspace, region, dbName: database }, - ...this.extraProps - }); - } - - public addGitBranchesEntry({ - workspace, - region, - database, - gitBranch, - xataBranch - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - gitBranch: string; - xataBranch: Schemas.BranchName; - }): Promise { - return operationsByTag.branch.addGitBranchesEntry({ - pathParams: { workspace, region, dbName: database }, - body: { gitBranch, xataBranch }, - ...this.extraProps - }); - } - - public removeGitBranchesEntry({ - workspace, - region, - database, - gitBranch - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - gitBranch: string; - }): Promise { - return operationsByTag.branch.removeGitBranchesEntry({ - pathParams: { workspace, region, dbName: database }, - queryParams: { gitBranch }, - ...this.extraProps - }); - } - - public resolveBranch({ - workspace, - region, - database, - gitBranch, - fallbackBranch - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - gitBranch?: string; - fallbackBranch?: string; - }): Promise { - return operationsByTag.branch.resolveBranch({ - pathParams: { workspace, region, dbName: database }, - queryParams: { gitBranch, fallbackBranch }, - ...this.extraProps - }); - } - - public pgRollMigrationHistory({ - workspace, - region, - database, - branch - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - }): Promise { - return operationsByTag.migrations.getMigrationHistory({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - ...this.extraProps - }); - } - - public applyMigration({ - workspace, - region, - database, - branch, - migration - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - migration: Schemas.Migration; - }): Promise { - return operationsByTag.migrations.applyMigration({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: migration, - ...this.extraProps - }); - } -} - -class TableApi { - constructor(private extraProps: ApiExtraProps) {} - - public createTable({ - workspace, - region, - database, - branch, - table - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - }): Promise { - return operationsByTag.table.createTable({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - ...this.extraProps - }); - } - - public deleteTable({ - workspace, - region, - database, - branch, - table - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - }): Promise { - return operationsByTag.table.deleteTable({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - ...this.extraProps - }); - } - - public updateTable({ - workspace, - region, - database, - branch, - table, - update - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - update: Types.UpdateTableRequestBody; - }): Promise { - return operationsByTag.table.updateTable({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - body: update, - ...this.extraProps - }); - } - - public getTableSchema({ - workspace, - region, - database, - branch, - table - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - }): Promise { - return operationsByTag.table.getTableSchema({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - ...this.extraProps - }); - } - - public setTableSchema({ - workspace, - region, - database, - branch, - table, - schema - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - schema: Types.SetTableSchemaRequestBody; - }): Promise { - return operationsByTag.table.setTableSchema({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - body: schema, - ...this.extraProps - }); - } - - public getTableColumns({ - workspace, - region, - database, - branch, - table - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - }): Promise { - return operationsByTag.table.getTableColumns({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - ...this.extraProps - }); - } - - public addTableColumn({ - workspace, - region, - database, - branch, - table, - column - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - column: Schemas.Column; - }): Promise { - return operationsByTag.table.addTableColumn({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - body: column, - ...this.extraProps - }); - } - - public getColumn({ - workspace, - region, - database, - branch, - table, - column - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - column: Schemas.ColumnName; - }): Promise { - return operationsByTag.table.getColumn({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table, columnName: column }, - ...this.extraProps - }); - } - - public updateColumn({ - workspace, - region, - database, - branch, - table, - column, - update - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - column: Schemas.ColumnName; - update: Types.UpdateColumnRequestBody; - }): Promise { - return operationsByTag.table.updateColumn({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table, columnName: column }, - body: update, - ...this.extraProps - }); - } - - public deleteColumn({ - workspace, - region, - database, - branch, - table, - column - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - column: Schemas.ColumnName; - }): Promise { - return operationsByTag.table.deleteColumn({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table, columnName: column }, - ...this.extraProps - }); - } -} - -class RecordsApi { - constructor(private extraProps: ApiExtraProps) {} - - public insertRecord({ - workspace, - region, - database, - branch, - table, - record, - columns - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - record: Record; - columns?: Schemas.ColumnsProjection; - }): Promise { - return operationsByTag.records.insertRecord({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - queryParams: { columns }, - body: record, - ...this.extraProps - }); - } - - public getRecord({ - workspace, - region, - database, - branch, - table, - id, - columns - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - id: Schemas.RecordID; - columns?: Schemas.ColumnsProjection; - }): Promise { - return operationsByTag.records.getRecord({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table, recordId: id }, - queryParams: { columns }, - ...this.extraProps - }); - } - - public insertRecordWithID({ - workspace, - region, - database, - branch, - table, - id, - record, - columns, - createOnly, - ifVersion - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - id: Schemas.RecordID; - record: Record; - columns?: Schemas.ColumnsProjection; - createOnly?: boolean; - ifVersion?: number; - }): Promise { - return operationsByTag.records.insertRecordWithID({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table, recordId: id }, - queryParams: { columns, createOnly, ifVersion }, - body: record, - ...this.extraProps - }); - } - - public updateRecordWithID({ - workspace, - region, - database, - branch, - table, - id, - record, - columns, - ifVersion - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - id: Schemas.RecordID; - record: Record; - columns?: Schemas.ColumnsProjection; - ifVersion?: number; - }): Promise { - return operationsByTag.records.updateRecordWithID({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table, recordId: id }, - queryParams: { columns, ifVersion }, - body: record, - ...this.extraProps - }); - } - - public upsertRecordWithID({ - workspace, - region, - database, - branch, - table, - id, - record, - columns, - ifVersion - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - id: Schemas.RecordID; - record: Record; - columns?: Schemas.ColumnsProjection; - ifVersion?: number; - }): Promise { - return operationsByTag.records.upsertRecordWithID({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table, recordId: id }, - queryParams: { columns, ifVersion }, - body: record, - ...this.extraProps - }); - } - - public deleteRecord({ - workspace, - region, - database, - branch, - table, - id, - columns - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - id: Schemas.RecordID; - columns?: Schemas.ColumnsProjection; - }): Promise { - return operationsByTag.records.deleteRecord({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table, recordId: id }, - queryParams: { columns }, - ...this.extraProps - }); - } - - public bulkInsertTableRecords({ - workspace, - region, - database, - branch, - table, - records, - columns - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - records: Record[]; - columns?: Schemas.ColumnsProjection; - }): Promise { - return operationsByTag.records.bulkInsertTableRecords({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - queryParams: { columns }, - body: { records }, - ...this.extraProps - }); - } - - public branchTransaction({ - workspace, - region, - database, - branch, - operations - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - operations: Schemas.TransactionOperation[]; - }): Promise { - return operationsByTag.records.branchTransaction({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: { operations }, - ...this.extraProps - }); - } -} - -class FilesApi { - constructor(private extraProps: ApiExtraProps) {} - - public getFileItem({ - workspace, - region, - database, - branch, - table, - record, - column, - fileId - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - record: Schemas.RecordID; - column: Schemas.ColumnName; - fileId: string; - }): Promise { - return operationsByTag.files.getFileItem({ - pathParams: { - workspace, - region, - dbBranchName: `${database}:${branch}`, - tableName: table, - recordId: record, - columnName: column, - fileId - }, - ...this.extraProps - }); - } - - public putFileItem({ - workspace, - region, - database, - branch, - table, - record, - column, - fileId, - file - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - record: Schemas.RecordID; - column: Schemas.ColumnName; - fileId: string; - file: any; - }): Promise { - return operationsByTag.files.putFileItem({ - pathParams: { - workspace, - region, - dbBranchName: `${database}:${branch}`, - tableName: table, - recordId: record, - columnName: column, - fileId - }, - // @ts-ignore - body: file, - ...this.extraProps - }); - } - - public deleteFileItem({ - workspace, - region, - database, - branch, - table, - record, - column, - fileId - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - record: Schemas.RecordID; - column: Schemas.ColumnName; - fileId: string; - }): Promise { - return operationsByTag.files.deleteFileItem({ - pathParams: { - workspace, - region, - dbBranchName: `${database}:${branch}`, - tableName: table, - recordId: record, - columnName: column, - fileId - }, - ...this.extraProps - }); - } - - public getFile({ - workspace, - region, - database, - branch, - table, - record, - column - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - record: Schemas.RecordID; - column: Schemas.ColumnName; - }): Promise { - return operationsByTag.files.getFile({ - pathParams: { - workspace, - region, - dbBranchName: `${database}:${branch}`, - tableName: table, - recordId: record, - columnName: column - }, - ...this.extraProps - }); - } - - public putFile({ - workspace, - region, - database, - branch, - table, - record, - column, - file - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - record: Schemas.RecordID; - column: Schemas.ColumnName; - file: Blob; - }): Promise { - return operationsByTag.files.putFile({ - pathParams: { - workspace, - region, - dbBranchName: `${database}:${branch}`, - tableName: table, - recordId: record, - columnName: column - }, - body: file, - ...this.extraProps - }); - } - - public deleteFile({ - workspace, - region, - database, - branch, - table, - record, - column - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - record: Schemas.RecordID; - column: Schemas.ColumnName; - }): Promise { - return operationsByTag.files.deleteFile({ - pathParams: { - workspace, - region, - dbBranchName: `${database}:${branch}`, - tableName: table, - recordId: record, - columnName: column - }, - ...this.extraProps - }); - } - - public fileAccess({ - workspace, - region, - fileId, - verify - }: { - workspace: Schemas.WorkspaceID; - region: string; - fileId: string; - verify?: Schemas.FileSignature; - }): Promise { - return operationsByTag.files.fileAccess({ - pathParams: { - workspace, - region, - fileId - }, - queryParams: { verify }, - ...this.extraProps - }); - } -} - -class SearchAndFilterApi { - constructor(private extraProps: ApiExtraProps) {} - - public queryTable({ - workspace, - region, - database, - branch, - table, - filter, - sort, - page, - columns, - consistency - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - filter?: Schemas.FilterExpression; - sort?: Schemas.SortExpression; - page?: Schemas.PageConfig; - columns?: Schemas.ColumnsProjection; - consistency?: 'strong' | 'eventual'; - }): Promise { - return operationsByTag.searchAndFilter.queryTable({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - body: { filter, sort, page, columns, consistency }, - ...this.extraProps - }); - } - - public searchTable({ - workspace, - region, - database, - branch, - table, - query, - fuzziness, - target, - prefix, - filter, - highlight, - boosters - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - query: string; - fuzziness?: Schemas.FuzzinessExpression; - target?: Schemas.TargetExpression; - prefix?: Schemas.PrefixExpression; - filter?: Schemas.FilterExpression; - highlight?: Schemas.HighlightExpression; - boosters?: Schemas.BoosterExpression[]; - }): Promise { - return operationsByTag.searchAndFilter.searchTable({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - body: { query, fuzziness, target, prefix, filter, highlight, boosters }, - ...this.extraProps - }); - } - - public searchBranch({ - workspace, - region, - database, - branch, - tables, - query, - fuzziness, - prefix, - highlight - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - tables?: ( - | string - | { - table: string; - filter?: Schemas.FilterExpression; - target?: Schemas.TargetExpression; - boosters?: Schemas.BoosterExpression[]; +type UserProps = { + headers?: Record; +}; + +type XataApiProxy = { + [Tag in keyof typeof operationsByTag]: { + [Method in keyof (typeof operationsByTag)[Tag]]: (typeof operationsByTag)[Tag][Method] extends infer Operation extends ( + ...args: any + ) => any + ? Omit[0], keyof ApiExtraProps> extends infer Params + ? RequiredKeys extends never + ? (params?: Params & UserProps) => ReturnType + : (params: Params & UserProps) => ReturnType + : never + : never; + }; +}; + +const buildApiClient = () => + class { + constructor(options: XataApiClientOptions = {}) { + const provider = options.host ?? 'production'; + const apiKey = options.apiKey ?? getAPIKey(); + const trace = options.trace ?? defaultTrace; + const clientID = generateUUID(); + + if (!apiKey) { + throw new Error('Could not resolve a valid apiKey'); + } + + const extraProps: ApiExtraProps = { + apiUrl: getHostUrl(provider, 'main'), + workspacesApiUrl: getHostUrl(provider, 'workspaces'), + fetch: getFetchImplementation(options.fetch), + apiKey, + trace, + clientName: options.clientName, + xataAgentExtra: options.xataAgentExtra, + clientID + }; + + return new Proxy(this, { + get: (_target, namespace: keyof typeof operationsByTag) => { + if (operationsByTag[namespace] === undefined) { + return undefined; + } + + return new Proxy( + {}, + { + get: (_target, operation: keyof (typeof operationsByTag)[keyof typeof operationsByTag]) => { + if (operationsByTag[namespace][operation] === undefined) { + return undefined; + } + + const method = operationsByTag[namespace][operation] as any; + + return async (params: Record) => { + return await method({ ...params, ...extraProps }); + }; + } + } + ); } - )[]; - query: string; - fuzziness?: Schemas.FuzzinessExpression; - prefix?: Schemas.PrefixExpression; - highlight?: Schemas.HighlightExpression; - }): Promise { - return operationsByTag.searchAndFilter.searchBranch({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: { tables, query, fuzziness, prefix, highlight }, - ...this.extraProps - }); - } - - public vectorSearchTable({ - workspace, - region, - database, - branch, - table, - queryVector, - column, - similarityFunction, - size, - filter - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - queryVector: number[]; - column: string; - similarityFunction?: string; - size?: number; - filter?: Schemas.FilterExpression; - }): Promise { - return operationsByTag.searchAndFilter.vectorSearchTable({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - body: { queryVector, column, similarityFunction, size, filter }, - ...this.extraProps - }); - } - - public askTable({ - workspace, - region, - database, - branch, - table, - options - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - options: Components.AskTableRequestBody; - }): Promise { - return operationsByTag.searchAndFilter.askTable({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - body: { ...options }, - ...this.extraProps - }); - } - - public askTableSession({ - workspace, - region, - database, - branch, - table, - sessionId, - message - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - sessionId: string; - message: string; - }): Promise { - return operationsByTag.searchAndFilter.askTableSession({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table, sessionId }, - body: { message }, - ...this.extraProps - }); - } - - public summarizeTable({ - workspace, - region, - database, - branch, - table, - filter, - columns, - summaries, - sort, - summariesFilter, - page, - consistency - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - filter?: Schemas.FilterExpression; - columns?: Schemas.ColumnsProjection; - summaries?: Schemas.SummaryExpressionList; - sort?: Schemas.SortExpression; - summariesFilter?: Schemas.FilterExpression; - page?: { size?: number }; - consistency?: 'strong' | 'eventual'; - }): Promise { - return operationsByTag.searchAndFilter.summarizeTable({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - body: { filter, columns, summaries, sort, summariesFilter, page, consistency }, - ...this.extraProps - }); - } - - public aggregateTable({ - workspace, - region, - database, - branch, - table, - filter, - aggs - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - table: Schemas.TableName; - filter?: Schemas.FilterExpression; - aggs?: Schemas.AggExpressionMap; - }): Promise { - return operationsByTag.searchAndFilter.aggregateTable({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, tableName: table }, - body: { filter, aggs }, - ...this.extraProps - }); - } -} - -class MigrationRequestsApi { - constructor(private extraProps: ApiExtraProps) {} - - public queryMigrationRequests({ - workspace, - region, - database, - filter, - sort, - page, - columns - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - filter?: Schemas.FilterExpression; - sort?: Schemas.SortExpression; - page?: Schemas.PageConfig; - columns?: Schemas.ColumnsProjection; - }): Promise { - return operationsByTag.migrationRequests.queryMigrationRequests({ - pathParams: { workspace, region, dbName: database }, - body: { filter, sort, page, columns }, - ...this.extraProps - }); - } - - public createMigrationRequest({ - workspace, - region, - database, - migration - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - migration: Components.CreateMigrationRequestRequestBody; - }): Promise { - return operationsByTag.migrationRequests.createMigrationRequest({ - pathParams: { workspace, region, dbName: database }, - body: migration, - ...this.extraProps - }); - } - - public getMigrationRequest({ - workspace, - region, - database, - migrationRequest - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - migrationRequest: Schemas.MigrationRequestNumber; - }): Promise { - return operationsByTag.migrationRequests.getMigrationRequest({ - pathParams: { workspace, region, dbName: database, mrNumber: migrationRequest }, - ...this.extraProps - }); - } - - public updateMigrationRequest({ - workspace, - region, - database, - migrationRequest, - update - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - migrationRequest: Schemas.MigrationRequestNumber; - update: Components.UpdateMigrationRequestRequestBody; - }): Promise { - return operationsByTag.migrationRequests.updateMigrationRequest({ - pathParams: { workspace, region, dbName: database, mrNumber: migrationRequest }, - body: update, - ...this.extraProps - }); - } - - public listMigrationRequestsCommits({ - workspace, - region, - database, - migrationRequest, - page - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - migrationRequest: Schemas.MigrationRequestNumber; - page?: { after?: string; before?: string; size?: number }; - }): Promise { - return operationsByTag.migrationRequests.listMigrationRequestsCommits({ - pathParams: { workspace, region, dbName: database, mrNumber: migrationRequest }, - body: { page }, - ...this.extraProps - }); - } - - public compareMigrationRequest({ - workspace, - region, - database, - migrationRequest - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - migrationRequest: Schemas.MigrationRequestNumber; - }): Promise { - return operationsByTag.migrationRequests.compareMigrationRequest({ - pathParams: { workspace, region, dbName: database, mrNumber: migrationRequest }, - ...this.extraProps - }); - } - - public getMigrationRequestIsMerged({ - workspace, - region, - database, - migrationRequest - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - migrationRequest: Schemas.MigrationRequestNumber; - }): Promise { - return operationsByTag.migrationRequests.getMigrationRequestIsMerged({ - pathParams: { workspace, region, dbName: database, mrNumber: migrationRequest }, - ...this.extraProps - }); - } - - public mergeMigrationRequest({ - workspace, - region, - database, - migrationRequest - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - migrationRequest: Schemas.MigrationRequestNumber; - }): Promise { - return operationsByTag.migrationRequests.mergeMigrationRequest({ - pathParams: { workspace, region, dbName: database, mrNumber: migrationRequest }, - ...this.extraProps - }); - } -} - -class MigrationsApi { - constructor(private extraProps: ApiExtraProps) {} - - public getBranchMigrationHistory({ - workspace, - region, - database, - branch, - limit, - startFrom - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - limit?: number; - startFrom?: string; - }): Promise { - return operationsByTag.migrations.getBranchMigrationHistory({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: { limit, startFrom }, - ...this.extraProps - }); - } - - public getBranchMigrationPlan({ - workspace, - region, - database, - branch, - schema - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - schema: Schemas.Schema; - }): Promise { - return operationsByTag.migrations.getBranchMigrationPlan({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: schema, - ...this.extraProps - }); - } - - public executeBranchMigrationPlan({ - workspace, - region, - database, - branch, - plan - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - plan: Types.ExecuteBranchMigrationPlanRequestBody; - }): Promise { - return operationsByTag.migrations.executeBranchMigrationPlan({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: plan, - ...this.extraProps - }); - } - - public getBranchSchemaHistory({ - workspace, - region, - database, - branch, - page - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - page?: { after?: string; before?: string; size?: number }; - }): Promise { - return operationsByTag.migrations.getBranchSchemaHistory({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: { page }, - ...this.extraProps - }); - } - - public compareBranchWithUserSchema({ - workspace, - region, - database, - branch, - schema, - schemaOperations, - branchOperations - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - schema: Schemas.Schema; - schemaOperations?: Schemas.MigrationOp[]; - branchOperations?: Schemas.MigrationOp[]; - }): Promise { - return operationsByTag.migrations.compareBranchWithUserSchema({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: { schema, schemaOperations, branchOperations }, - ...this.extraProps - }); - } - - public compareBranchSchemas({ - workspace, - region, - database, - branch, - compare, - sourceBranchOperations, - targetBranchOperations - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - compare: Schemas.BranchName; - sourceBranchOperations?: Schemas.MigrationOp[]; - targetBranchOperations?: Schemas.MigrationOp[]; - }): Promise { - return operationsByTag.migrations.compareBranchSchemas({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}`, branchName: compare }, - body: { sourceBranchOperations, targetBranchOperations }, - ...this.extraProps - }); - } - - public updateBranchSchema({ - workspace, - region, - database, - branch, - migration - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - migration: Schemas.Migration; - }): Promise { - return operationsByTag.migrations.updateBranchSchema({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: migration, - ...this.extraProps - }); - } - - public previewBranchSchemaEdit({ - workspace, - region, - database, - branch, - data - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - data: { edits?: Schemas.SchemaEditScript }; - }): Promise { - return operationsByTag.migrations.previewBranchSchemaEdit({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: data, - ...this.extraProps - }); - } - - public applyBranchSchemaEdit({ - workspace, - region, - database, - branch, - edits - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - edits: Schemas.SchemaEditScript; - }): Promise { - return operationsByTag.migrations.applyBranchSchemaEdit({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: { edits }, - ...this.extraProps - }); - } - - public pushBranchMigrations({ - workspace, - region, - database, - branch, - migrations - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - migrations: Schemas.MigrationObject[]; - }): Promise { - return operationsByTag.migrations.pushBranchMigrations({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - body: { migrations }, - ...this.extraProps - }); - } - - public getSchema({ - workspace, - region, - database, - branch - }: { - workspace: Schemas.WorkspaceID; - region: string; - database: Schemas.DBName; - branch: Schemas.BranchName; - }): Promise { - return operationsByTag.migrations.getSchema({ - pathParams: { workspace, region, dbBranchName: `${database}:${branch}` }, - ...this.extraProps - }); - } -} - -class DatabaseApi { - constructor(private extraProps: ApiExtraProps) {} - - public getDatabaseList({ workspace }: { workspace: Schemas.WorkspaceID }): Promise { - return operationsByTag.databases.getDatabaseList({ - pathParams: { workspaceId: workspace }, - ...this.extraProps - }); - } - - public createDatabase({ - workspace, - database, - data, - headers - }: { - workspace: Schemas.WorkspaceID; - database: Schemas.DBName; - data: Components.CreateDatabaseRequestBody; - headers?: Record; - }): Promise { - return operationsByTag.databases.createDatabase({ - pathParams: { workspaceId: workspace, dbName: database }, - body: data, - headers, - ...this.extraProps - }); - } - - public deleteDatabase({ - workspace, - database - }: { - workspace: Schemas.WorkspaceID; - database: Schemas.DBName; - }): Promise { - return operationsByTag.databases.deleteDatabase({ - pathParams: { workspaceId: workspace, dbName: database }, - ...this.extraProps - }); - } - - public getDatabaseMetadata({ - workspace, - database - }: { - workspace: Schemas.WorkspaceID; - database: Schemas.DBName; - }): Promise { - return operationsByTag.databases.getDatabaseMetadata({ - pathParams: { workspaceId: workspace, dbName: database }, - ...this.extraProps - }); - } - - public updateDatabaseMetadata({ - workspace, - database, - metadata - }: { - workspace: Schemas.WorkspaceID; - database: Schemas.DBName; - metadata: Schemas.DatabaseMetadata; - }): Promise { - return operationsByTag.databases.updateDatabaseMetadata({ - pathParams: { workspaceId: workspace, dbName: database }, - body: metadata, - ...this.extraProps - }); - } - - public renameDatabase({ - workspace, - database, - newName - }: { - workspace: Schemas.WorkspaceID; - database: Schemas.DBName; - newName: Schemas.DBName; - }): Promise { - return operationsByTag.databases.renameDatabase({ - pathParams: { workspaceId: workspace, dbName: database }, - body: { newName }, - ...this.extraProps - }); - } - - public getDatabaseGithubSettings({ - workspace, - database - }: { - workspace: Schemas.WorkspaceID; - database: Schemas.DBName; - }): Promise { - return operationsByTag.databases.getDatabaseGithubSettings({ - pathParams: { workspaceId: workspace, dbName: database }, - ...this.extraProps - }); - } - - public updateDatabaseGithubSettings({ - workspace, - database, - settings - }: { - workspace: Schemas.WorkspaceID; - database: Schemas.DBName; - settings: Schemas.DatabaseGithubSettings; - }): Promise { - return operationsByTag.databases.updateDatabaseGithubSettings({ - pathParams: { workspaceId: workspace, dbName: database }, - body: settings, - ...this.extraProps - }); - } - - public deleteDatabaseGithubSettings({ - workspace, - database - }: { - workspace: Schemas.WorkspaceID; - database: Schemas.DBName; - }): Promise { - return operationsByTag.databases.deleteDatabaseGithubSettings({ - pathParams: { workspaceId: workspace, dbName: database }, - ...this.extraProps - }); - } + }); + } + } as unknown as { new (options?: XataApiClientOptions): XataApiProxy }; - public listRegions({ workspace }: { workspace: Schemas.WorkspaceID }): Promise { - return operationsByTag.databases.listRegions({ - pathParams: { workspaceId: workspace }, - ...this.extraProps - }); - } -} +export class XataApiClient extends buildApiClient() {} diff --git a/packages/client/src/util/types.ts b/packages/client/src/util/types.ts index 95c0bc8c0..7fc3d8b63 100644 --- a/packages/client/src/util/types.ts +++ b/packages/client/src/util/types.ts @@ -65,3 +65,11 @@ type Narrowable = string | number | bigint | boolean; type Try = A1 extends A2 ? A1 : Catch; export type Narrow = Try>; + +export type RequiredKeys = { + [K in keyof T]-?: {} extends Pick ? never : K; +}[keyof T]; + +export type FlattenObject = { + [K in keyof T]: T[K]; +}[keyof T]; diff --git a/packages/importer/src/importer.ts b/packages/importer/src/importer.ts index 77fa73896..f01b44907 100644 --- a/packages/importer/src/importer.ts +++ b/packages/importer/src/importer.ts @@ -8,8 +8,9 @@ export const importBatch = async ( pluginOptions: XataPluginOptions, errors?: ImportError[], maxRetries = 10, - retries = 0 + retries?: number ): Promise<{ ids: Array; errors?: ImportError[] }> => { + if (!retries) retries = 0; const { batchRows } = options; const operations = batchRows.map((row) => { return { @@ -44,7 +45,16 @@ export const importBatch = async ( // what if errors twice? const errors = rowErrors.map((e: any) => ({ row: batchRows[e.index], error: e.message, index: e.index })); - return importBatch(location, { ...options, batchRows: rowsToRetry }, pluginOptions, errors, maxRetries, retries); + if (retries < maxRetries) { + return importBatch( + location, + { ...options, batchRows: rowsToRetry }, + pluginOptions, + errors, + maxRetries, + retries + 1 + ); + } } if (retries < maxRetries) { // exponential backoff diff --git a/packages/plugin-client-drizzle/test/drizzle.test.ts b/packages/plugin-client-drizzle/test/drizzle.test.ts index 4f4fd077a..213e68dbc 100644 --- a/packages/plugin-client-drizzle/test/drizzle.test.ts +++ b/packages/plugin-client-drizzle/test/drizzle.test.ts @@ -78,10 +78,9 @@ function getDrizzleClient(type: string, branch: string) { describe.concurrent.each([{ type: 'pg' }, { type: 'http' }])('Drizzle $type', ({ type }) => { beforeAll(async () => { - await api.database.createDatabase({ - workspace, - database, - data: { region, branchName: 'main' }, + await api.databases.createDatabase({ + pathParams: { workspaceId: workspace, dbName: database }, + body: { region, branchName: 'main' }, headers: { 'X-Features': 'feat-pgroll-migrations=1' } }); @@ -155,12 +154,15 @@ describe.concurrent.each([{ type: 'pg' }, { type: 'http' }])('Drizzle $type', ({ }); afterAll(async () => { - await api.database.deleteDatabase({ workspace, database }); + await api.databases.deleteDatabase({ pathParams: { workspaceId: workspace, dbName: database } }); }); beforeEach(async (ctx) => { ctx.branch = `test-${Math.random().toString(36).substring(7)}`; - await api.branches.createBranch({ workspace, database, region, branch: ctx.branch, from: 'main' }); + await api.branch.createBranch({ + pathParams: { workspace, region, dbBranchName: `${database}:${ctx.branch}` }, + body: { from: 'main' } + }); const { db, client } = getDrizzleClient(type, ctx.branch); await client?.connect(); @@ -171,7 +173,7 @@ describe.concurrent.each([{ type: 'pg' }, { type: 'http' }])('Drizzle $type', ({ afterEach(async (ctx) => { await ctx.client?.end(); - await api.branches.deleteBranch({ workspace, database, region, branch: ctx.branch }); + await api.branch.deleteBranch({ pathParams: { workspace, region, dbBranchName: `${database}:${ctx.branch}` } }); }); /* @@ -6285,7 +6287,7 @@ describe.concurrent.each([{ type: 'pg' }, { type: 'http' }])('Drizzle $type', ({ async function waitForReplication(): Promise { try { await new Promise((resolve) => setTimeout(resolve, 2000)); - await api.branches.getBranchList({ workspace, database, region }); + await api.branch.getBranchList({ pathParams: { workspace, dbName: database, region } }); } catch (error) { console.log(`Replication not ready yet, retrying...`); return await waitForReplication(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b60ce60cf..10b2aa4c6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,34 +46,34 @@ importers: version: 1.9.0 '@opentelemetry/exporter-trace-otlp-grpc': specifier: ^0.52.0 - version: 0.52.0(@opentelemetry/api@1.9.0) + version: 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': specifier: ^0.52.0 - version: 0.52.0(@opentelemetry/api@1.9.0) + version: 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/resources': specifier: ^1.25.0 - version: 1.25.0(@opentelemetry/api@1.9.0) + version: 1.25.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': specifier: ^1.25.0 - version: 1.25.0(@opentelemetry/api@1.9.0) + version: 1.25.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-node': specifier: ^1.25.0 - version: 1.25.0(@opentelemetry/api@1.9.0) + version: 1.25.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': specifier: ^1.25.0 - version: 1.25.0 + version: 1.25.1 '@size-limit/preset-small-lib': specifier: ^11.1.4 version: 11.1.4(size-limit@11.1.4) '@types/node': specifier: ^20.14.2 - version: 20.14.2 + version: 20.14.7 '@typescript-eslint/eslint-plugin': specifier: ^7.13.0 - version: 7.13.0(@typescript-eslint/parser@7.13.0)(eslint@9.5.0)(typescript@5.4.5) + version: 7.13.1(@typescript-eslint/parser@7.13.1)(eslint@9.5.0)(typescript@5.4.5) '@typescript-eslint/parser': specifier: ^7.13.0 - version: 7.13.0(eslint@9.5.0)(typescript@5.4.5) + version: 7.13.1(eslint@9.5.0)(typescript@5.4.5) doctoc: specifier: ^2.2.1 version: 2.2.1 @@ -85,10 +85,10 @@ importers: version: 9.5.0 eslint-import-resolver-typescript: specifier: ^3.6.1 - version: 3.6.1(@typescript-eslint/parser@7.13.0)(eslint-plugin-import@2.29.1)(eslint@9.5.0) + version: 3.6.1(@typescript-eslint/parser@7.13.1)(eslint-plugin-import@2.29.1)(eslint@9.5.0) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.13.0)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0) + version: 2.29.1(@typescript-eslint/parser@7.13.1)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0) husky: specifier: ^9.0.11 version: 9.0.11 @@ -115,7 +115,7 @@ importers: version: 6.1.1(rollup@4.18.0)(typescript@5.4.5) rollup-plugin-esbuild: specifier: ^6.1.1 - version: 6.1.1(esbuild@0.21.5)(rollup@4.18.0) + version: 6.1.1(esbuild@0.21.3)(rollup@4.18.0) rollup-plugin-node-builtins: specifier: ^2.1.2 version: 2.1.2 @@ -133,10 +133,10 @@ importers: version: 11.1.4 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@20.14.2)(typescript@5.4.5) + version: 10.9.2(@types/node@20.14.7)(typescript@5.4.5) tsx: specifier: ^4.15.5 - version: 4.15.5 + version: 4.15.7 turbo: specifier: ^2.0.4 version: 2.0.4 @@ -145,13 +145,13 @@ importers: version: 5.4.5 typescript-eslint: specifier: ^7.13.0 - version: 7.13.0(eslint@9.5.0)(typescript@5.4.5) + version: 7.13.1(eslint@9.5.0)(typescript@5.4.5) vite: specifier: ^5.3.1 - version: 5.3.1(@types/node@20.14.2) + version: 5.3.1(@types/node@20.14.7) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@20.14.2) + version: 1.6.0(@types/node@20.14.7) zod: specifier: ^3.23.8 version: 3.23.8 @@ -227,6 +227,9 @@ importers: lodash.get: specifier: ^4.4.2 version: 4.4.2 + lodash.keyby: + specifier: ^4.6.0 + version: 4.6.0 lodash.set: specifier: ^4.3.2 version: 4.3.2 @@ -254,6 +257,9 @@ importers: tslib: specifier: ^2.6.3 version: 2.6.3 + type-fest: + specifier: ^4.18.1 + version: 4.18.1 which: specifier: ^4.0.0 version: 4.0.0 @@ -273,6 +279,9 @@ importers: '@types/lodash.get': specifier: ^4.4.9 version: 4.4.9 + '@types/lodash.keyby': + specifier: ^4.6.9 + version: 4.6.9 '@types/lodash.set': specifier: ^4.3.9 version: 4.3.9 @@ -299,13 +308,13 @@ importers: version: 3.1.8(eslint@9.5.0)(typescript@5.4.5) oclif: specifier: ^4.13.7 - version: 4.13.7 + version: 4.13.8 shx: specifier: ^0.3.4 version: 0.3.4 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@20.14.2)(typescript@5.4.5) + version: 10.9.2(@types/node@20.14.7)(typescript@5.4.5) typescript: specifier: ^5.4.5 version: 5.4.5 @@ -401,7 +410,7 @@ importers: version: 22.0.0 tsx: specifier: ^4.15.5 - version: 4.15.5 + version: 4.15.7 packages/plugin-client-cache: dependencies: @@ -417,7 +426,7 @@ importers: dependencies: '@cloudflare/workers-types': specifier: ^4.20240614.0 - version: 4.20240614.0 + version: 4.20240620.0 '@xata.io/client': specifier: workspace:* version: link:../client @@ -455,7 +464,7 @@ importers: version: 7.24.7 '@netlify/build': specifier: '=29.20.6' - version: 29.20.6(@types/node@20.14.2) + version: 29.20.6(@types/node@20.14.7) '@xata.io/client': specifier: workspace:* version: link:../client @@ -465,7 +474,7 @@ importers: version: 7.20.5 '@types/node': specifier: ^20.14.2 - version: 20.14.2 + version: 20.14.7 typescript: specifier: ^5.4.5 version: 5.4.5 @@ -582,6 +591,19 @@ packages: tslib: 1.14.1 dev: true + /@aws-crypto/sha256-browser@5.2.0: + resolution: + { integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw== } + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-locate-window': 3.465.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.6.3 + dev: true + /@aws-crypto/sha256-js@3.0.0: resolution: { integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ== } @@ -591,6 +613,16 @@ packages: tslib: 1.14.1 dev: true + /@aws-crypto/sha256-js@5.2.0: + resolution: + { integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA== } + engines: { node: '>=16.0.0' } + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.598.0 + tslib: 2.6.3 + dev: true + /@aws-crypto/supports-web-crypto@3.0.0: resolution: { integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg== } @@ -598,6 +630,13 @@ packages: tslib: 1.14.1 dev: true + /@aws-crypto/supports-web-crypto@5.2.0: + resolution: + { integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg== } + dependencies: + tslib: 2.6.3 + dev: true + /@aws-crypto/util@3.0.0: resolution: { integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w== } @@ -607,54 +646,63 @@ packages: tslib: 1.14.1 dev: true - /@aws-sdk/client-cloudfront@3.592.0: + /@aws-crypto/util@5.2.0: + resolution: + { integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ== } + dependencies: + '@aws-sdk/types': 3.598.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.6.3 + dev: true + + /@aws-sdk/client-cloudfront@3.600.0: resolution: - { integrity: sha512-V7tkLelihsPbtHvViY2H7YwUWtoIFIgh3HV/Bpc35ybMmVP/3GuMYJNu1TF73rxZzo5qr0NsXMPekzAxP84P8A== } + { integrity: sha512-5qO3lc6AvErAqia552zA8ADwFO3UiJpJ8R2jy7JL18RifmePVs/f0jPeWPtAoV81iehmFziLyu6pWUMnfh3EJg== } engines: { node: '>=16.0.0' } dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.592.0 - '@aws-sdk/client-sts': 3.592.0(@aws-sdk/client-sso-oidc@3.592.0) - '@aws-sdk/core': 3.592.0 - '@aws-sdk/credential-provider-node': 3.592.0(@aws-sdk/client-sso-oidc@3.592.0)(@aws-sdk/client-sts@3.592.0) - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.587.0 - '@aws-sdk/region-config-resolver': 3.587.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.587.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.587.0 - '@aws-sdk/xml-builder': 3.575.0 - '@smithy/config-resolver': 3.0.1 - '@smithy/core': 2.2.0 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.1 - '@smithy/middleware-retry': 3.0.3 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.1.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.1.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sso-oidc': 3.600.0(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/client-sts': 3.600.0 + '@aws-sdk/core': 3.598.0 + '@aws-sdk/credential-provider-node': 3.600.0(@aws-sdk/client-sso-oidc@3.600.0)(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/middleware-host-header': 3.598.0 + '@aws-sdk/middleware-logger': 3.598.0 + '@aws-sdk/middleware-recursion-detection': 3.598.0 + '@aws-sdk/middleware-user-agent': 3.598.0 + '@aws-sdk/region-config-resolver': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@aws-sdk/util-user-agent-browser': 3.598.0 + '@aws-sdk/util-user-agent-node': 3.598.0 + '@aws-sdk/xml-builder': 3.598.0 + '@smithy/config-resolver': 3.0.3 + '@smithy/core': 2.2.3 + '@smithy/fetch-http-handler': 3.1.0 + '@smithy/hash-node': 3.0.2 + '@smithy/invalid-dependency': 3.0.2 + '@smithy/middleware-content-length': 3.0.2 + '@smithy/middleware-endpoint': 3.0.3 + '@smithy/middleware-retry': 3.0.6 + '@smithy/middleware-serde': 3.0.2 + '@smithy/middleware-stack': 3.0.2 + '@smithy/node-config-provider': 3.1.2 + '@smithy/node-http-handler': 3.1.0 + '@smithy/protocol-http': 4.0.2 + '@smithy/smithy-client': 3.1.4 + '@smithy/types': 3.2.0 + '@smithy/url-parser': 3.0.2 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.3 - '@smithy/util-defaults-mode-node': 3.0.3 - '@smithy/util-endpoints': 2.0.1 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - '@smithy/util-stream': 3.0.1 + '@smithy/util-defaults-mode-browser': 3.0.6 + '@smithy/util-defaults-mode-node': 3.0.6 + '@smithy/util-endpoints': 2.0.3 + '@smithy/util-middleware': 3.0.2 + '@smithy/util-retry': 3.0.2 + '@smithy/util-stream': 3.0.4 '@smithy/util-utf8': 3.0.0 - '@smithy/util-waiter': 3.0.0 + '@smithy/util-waiter': 3.1.0 tslib: 2.6.3 transitivePeerDependencies: - aws-crt @@ -690,8 +738,8 @@ packages: '@aws-sdk/util-user-agent-browser': 3.577.0 '@aws-sdk/util-user-agent-node': 3.577.0 '@aws-sdk/xml-builder': 3.575.0 - '@smithy/config-resolver': 3.0.1 - '@smithy/core': 2.2.0 + '@smithy/config-resolver': 3.0.0 + '@smithy/core': 2.0.1 '@smithy/eventstream-serde-browser': 3.0.0 '@smithy/eventstream-serde-config-resolver': 3.0.0 '@smithy/eventstream-serde-node': 3.0.0 @@ -702,22 +750,22 @@ packages: '@smithy/invalid-dependency': 3.0.0 '@smithy/md5-js': 3.0.0 '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.1 - '@smithy/middleware-retry': 3.0.3 + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-retry': 3.0.1 '@smithy/middleware-serde': 3.0.0 '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.1.0 + '@smithy/node-config-provider': 3.0.0 '@smithy/node-http-handler': 3.0.0 '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.1.1 + '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 '@smithy/url-parser': 3.0.0 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.3 - '@smithy/util-defaults-mode-node': 3.0.3 - '@smithy/util-endpoints': 2.0.1 + '@smithy/util-defaults-mode-browser': 3.0.1 + '@smithy/util-defaults-mode-node': 3.0.1 + '@smithy/util-endpoints': 2.0.0 '@smithy/util-retry': 3.0.0 '@smithy/util-stream': 3.0.1 '@smithy/util-utf8': 3.0.0 @@ -746,28 +794,28 @@ packages: '@aws-sdk/util-endpoints': 3.583.0 '@aws-sdk/util-user-agent-browser': 3.577.0 '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.1 - '@smithy/core': 2.2.0 + '@smithy/config-resolver': 3.0.0 + '@smithy/core': 2.0.1 '@smithy/fetch-http-handler': 3.0.1 '@smithy/hash-node': 3.0.0 '@smithy/invalid-dependency': 3.0.0 '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.1 - '@smithy/middleware-retry': 3.0.3 + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-retry': 3.0.1 '@smithy/middleware-serde': 3.0.0 '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.1.0 + '@smithy/node-config-provider': 3.0.0 '@smithy/node-http-handler': 3.0.0 '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.1.1 + '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 '@smithy/url-parser': 3.0.0 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.3 - '@smithy/util-defaults-mode-node': 3.0.3 - '@smithy/util-endpoints': 2.0.1 + '@smithy/util-defaults-mode-browser': 3.0.1 + '@smithy/util-defaults-mode-node': 3.0.1 + '@smithy/util-endpoints': 2.0.0 '@smithy/util-middleware': 3.0.0 '@smithy/util-retry': 3.0.0 '@smithy/util-utf8': 3.0.0 @@ -776,52 +824,53 @@ packages: - aws-crt dev: true - /@aws-sdk/client-sso-oidc@3.592.0: + /@aws-sdk/client-sso-oidc@3.600.0(@aws-sdk/client-sts@3.600.0): resolution: - { integrity: sha512-11Zvm8nm0s/UF3XCjzFRpQU+8FFVW5rcr3BHfnH6xAe5JEoN6bJN/n+wOfnElnjek+90hh+Qc7s141AMrCjiiw== } + { integrity: sha512-7+I8RWURGfzvChyNQSyj5/tKrqRbzRl7H+BnTOf/4Vsw1nFOi5ROhlhD4X/Y0QCTacxnaoNcIrqnY7uGGvVRzw== } engines: { node: '>=16.0.0' } dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.592.0(@aws-sdk/client-sso-oidc@3.592.0) - '@aws-sdk/core': 3.592.0 - '@aws-sdk/credential-provider-node': 3.592.0(@aws-sdk/client-sso-oidc@3.592.0)(@aws-sdk/client-sts@3.592.0) - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.587.0 - '@aws-sdk/region-config-resolver': 3.587.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.587.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.587.0 - '@smithy/config-resolver': 3.0.1 - '@smithy/core': 2.2.0 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.1 - '@smithy/middleware-retry': 3.0.3 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.1.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.1.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sts': 3.600.0 + '@aws-sdk/core': 3.598.0 + '@aws-sdk/credential-provider-node': 3.600.0(@aws-sdk/client-sso-oidc@3.600.0)(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/middleware-host-header': 3.598.0 + '@aws-sdk/middleware-logger': 3.598.0 + '@aws-sdk/middleware-recursion-detection': 3.598.0 + '@aws-sdk/middleware-user-agent': 3.598.0 + '@aws-sdk/region-config-resolver': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@aws-sdk/util-user-agent-browser': 3.598.0 + '@aws-sdk/util-user-agent-node': 3.598.0 + '@smithy/config-resolver': 3.0.3 + '@smithy/core': 2.2.3 + '@smithy/fetch-http-handler': 3.1.0 + '@smithy/hash-node': 3.0.2 + '@smithy/invalid-dependency': 3.0.2 + '@smithy/middleware-content-length': 3.0.2 + '@smithy/middleware-endpoint': 3.0.3 + '@smithy/middleware-retry': 3.0.6 + '@smithy/middleware-serde': 3.0.2 + '@smithy/middleware-stack': 3.0.2 + '@smithy/node-config-provider': 3.1.2 + '@smithy/node-http-handler': 3.1.0 + '@smithy/protocol-http': 4.0.2 + '@smithy/smithy-client': 3.1.4 + '@smithy/types': 3.2.0 + '@smithy/url-parser': 3.0.2 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.3 - '@smithy/util-defaults-mode-node': 3.0.3 - '@smithy/util-endpoints': 2.0.1 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.6 + '@smithy/util-defaults-mode-node': 3.0.6 + '@smithy/util-endpoints': 2.0.3 + '@smithy/util-middleware': 3.0.2 + '@smithy/util-retry': 3.0.2 '@smithy/util-utf8': 3.0.0 tslib: 2.6.3 transitivePeerDependencies: + - '@aws-sdk/client-sts' - aws-crt dev: true @@ -842,28 +891,28 @@ packages: '@aws-sdk/util-endpoints': 3.583.0 '@aws-sdk/util-user-agent-browser': 3.577.0 '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.1 - '@smithy/core': 2.2.0 + '@smithy/config-resolver': 3.0.0 + '@smithy/core': 2.0.1 '@smithy/fetch-http-handler': 3.0.1 '@smithy/hash-node': 3.0.0 '@smithy/invalid-dependency': 3.0.0 '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.1 - '@smithy/middleware-retry': 3.0.3 + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-retry': 3.0.1 '@smithy/middleware-serde': 3.0.0 '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.1.0 + '@smithy/node-config-provider': 3.0.0 '@smithy/node-http-handler': 3.0.0 '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.1.1 + '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 '@smithy/url-parser': 3.0.0 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.3 - '@smithy/util-defaults-mode-node': 3.0.3 - '@smithy/util-endpoints': 2.0.1 + '@smithy/util-defaults-mode-browser': 3.0.1 + '@smithy/util-defaults-mode-node': 3.0.1 + '@smithy/util-endpoints': 2.0.0 '@smithy/util-middleware': 3.0.0 '@smithy/util-retry': 3.0.0 '@smithy/util-utf8': 3.0.0 @@ -872,47 +921,47 @@ packages: - aws-crt dev: true - /@aws-sdk/client-sso@3.592.0: + /@aws-sdk/client-sso@3.598.0: resolution: - { integrity: sha512-w+SuW47jQqvOC7fonyjFjsOh3yjqJ+VpWdVrmrl0E/KryBE7ho/Wn991Buf/EiHHeJikoWgHsAIPkBH29+ntdA== } + { integrity: sha512-nOI5lqPYa+YZlrrzwAJywJSw3MKVjvu6Ge2fCqQUNYMfxFB0NAaDFnl0EPjXi+sEbtCuz/uWE77poHbqiZ+7Iw== } engines: { node: '>=16.0.0' } dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.592.0 - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.587.0 - '@aws-sdk/region-config-resolver': 3.587.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.587.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.587.0 - '@smithy/config-resolver': 3.0.1 - '@smithy/core': 2.2.0 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.1 - '@smithy/middleware-retry': 3.0.3 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.1.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.1.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.598.0 + '@aws-sdk/middleware-host-header': 3.598.0 + '@aws-sdk/middleware-logger': 3.598.0 + '@aws-sdk/middleware-recursion-detection': 3.598.0 + '@aws-sdk/middleware-user-agent': 3.598.0 + '@aws-sdk/region-config-resolver': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@aws-sdk/util-user-agent-browser': 3.598.0 + '@aws-sdk/util-user-agent-node': 3.598.0 + '@smithy/config-resolver': 3.0.3 + '@smithy/core': 2.2.3 + '@smithy/fetch-http-handler': 3.1.0 + '@smithy/hash-node': 3.0.2 + '@smithy/invalid-dependency': 3.0.2 + '@smithy/middleware-content-length': 3.0.2 + '@smithy/middleware-endpoint': 3.0.3 + '@smithy/middleware-retry': 3.0.6 + '@smithy/middleware-serde': 3.0.2 + '@smithy/middleware-stack': 3.0.2 + '@smithy/node-config-provider': 3.1.2 + '@smithy/node-http-handler': 3.1.0 + '@smithy/protocol-http': 4.0.2 + '@smithy/smithy-client': 3.1.4 + '@smithy/types': 3.2.0 + '@smithy/url-parser': 3.0.2 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.3 - '@smithy/util-defaults-mode-node': 3.0.3 - '@smithy/util-endpoints': 2.0.1 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.6 + '@smithy/util-defaults-mode-node': 3.0.6 + '@smithy/util-endpoints': 2.0.3 + '@smithy/util-middleware': 3.0.2 + '@smithy/util-retry': 3.0.2 '@smithy/util-utf8': 3.0.0 tslib: 2.6.3 transitivePeerDependencies: @@ -938,28 +987,28 @@ packages: '@aws-sdk/util-endpoints': 3.583.0 '@aws-sdk/util-user-agent-browser': 3.577.0 '@aws-sdk/util-user-agent-node': 3.577.0 - '@smithy/config-resolver': 3.0.1 - '@smithy/core': 2.2.0 + '@smithy/config-resolver': 3.0.0 + '@smithy/core': 2.0.1 '@smithy/fetch-http-handler': 3.0.1 '@smithy/hash-node': 3.0.0 '@smithy/invalid-dependency': 3.0.0 '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.1 - '@smithy/middleware-retry': 3.0.3 + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-retry': 3.0.1 '@smithy/middleware-serde': 3.0.0 '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.1.0 + '@smithy/node-config-provider': 3.0.0 '@smithy/node-http-handler': 3.0.0 '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.1.1 + '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 '@smithy/url-parser': 3.0.0 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.3 - '@smithy/util-defaults-mode-node': 3.0.3 - '@smithy/util-endpoints': 2.0.1 + '@smithy/util-defaults-mode-browser': 3.0.1 + '@smithy/util-defaults-mode-node': 3.0.1 + '@smithy/util-endpoints': 2.0.0 '@smithy/util-middleware': 3.0.0 '@smithy/util-retry': 3.0.0 '@smithy/util-utf8': 3.0.0 @@ -969,53 +1018,52 @@ packages: - aws-crt dev: true - /@aws-sdk/client-sts@3.592.0(@aws-sdk/client-sso-oidc@3.592.0): + /@aws-sdk/client-sts@3.600.0: resolution: - { integrity: sha512-KUrOdszZfcrlpKr4dpdkGibZ/qq3Lnfu1rjv1U+V1QJQ9OuMo9J3sDWpWV9tigNqY0aGllarWH5cJbz9868W/w== } + { integrity: sha512-KQG97B7LvTtTiGmjlrG1LRAY8wUvCQzrmZVV5bjrJ/1oXAU7DITYwVbSJeX9NWg6hDuSk0VE3MFwIXS2SvfLIA== } engines: { node: '>=16.0.0' } dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.592.0 - '@aws-sdk/core': 3.592.0 - '@aws-sdk/credential-provider-node': 3.592.0(@aws-sdk/client-sso-oidc@3.592.0)(@aws-sdk/client-sts@3.592.0) - '@aws-sdk/middleware-host-header': 3.577.0 - '@aws-sdk/middleware-logger': 3.577.0 - '@aws-sdk/middleware-recursion-detection': 3.577.0 - '@aws-sdk/middleware-user-agent': 3.587.0 - '@aws-sdk/region-config-resolver': 3.587.0 - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.587.0 - '@aws-sdk/util-user-agent-browser': 3.577.0 - '@aws-sdk/util-user-agent-node': 3.587.0 - '@smithy/config-resolver': 3.0.1 - '@smithy/core': 2.2.0 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.1 - '@smithy/middleware-retry': 3.0.3 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.1.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.1.1 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sso-oidc': 3.600.0(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/core': 3.598.0 + '@aws-sdk/credential-provider-node': 3.600.0(@aws-sdk/client-sso-oidc@3.600.0)(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/middleware-host-header': 3.598.0 + '@aws-sdk/middleware-logger': 3.598.0 + '@aws-sdk/middleware-recursion-detection': 3.598.0 + '@aws-sdk/middleware-user-agent': 3.598.0 + '@aws-sdk/region-config-resolver': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@aws-sdk/util-user-agent-browser': 3.598.0 + '@aws-sdk/util-user-agent-node': 3.598.0 + '@smithy/config-resolver': 3.0.3 + '@smithy/core': 2.2.3 + '@smithy/fetch-http-handler': 3.1.0 + '@smithy/hash-node': 3.0.2 + '@smithy/invalid-dependency': 3.0.2 + '@smithy/middleware-content-length': 3.0.2 + '@smithy/middleware-endpoint': 3.0.3 + '@smithy/middleware-retry': 3.0.6 + '@smithy/middleware-serde': 3.0.2 + '@smithy/middleware-stack': 3.0.2 + '@smithy/node-config-provider': 3.1.2 + '@smithy/node-http-handler': 3.1.0 + '@smithy/protocol-http': 4.0.2 + '@smithy/smithy-client': 3.1.4 + '@smithy/types': 3.2.0 + '@smithy/url-parser': 3.0.2 '@smithy/util-base64': 3.0.0 '@smithy/util-body-length-browser': 3.0.0 '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.3 - '@smithy/util-defaults-mode-node': 3.0.3 - '@smithy/util-endpoints': 2.0.1 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.6 + '@smithy/util-defaults-mode-node': 3.0.6 + '@smithy/util-endpoints': 2.0.3 + '@smithy/util-middleware': 3.0.2 + '@smithy/util-retry': 3.0.2 '@smithy/util-utf8': 3.0.0 tslib: 2.6.3 transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - aws-crt dev: true @@ -1024,25 +1072,25 @@ packages: { integrity: sha512-ofmD96IQc9g1dbyqlCyxu5fCG7kIl9p1NoN5+vGBUyLdbmPCV3Pdg99nRHYEJuv2MgGx5AUFGDPMHcqbJpnZIw== } engines: { node: '>=16.0.0' } dependencies: - '@smithy/core': 2.2.0 + '@smithy/core': 2.0.1 '@smithy/protocol-http': 4.0.0 '@smithy/signature-v4': 3.0.0 - '@smithy/smithy-client': 3.1.1 + '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 fast-xml-parser: 4.2.5 tslib: 2.6.3 dev: true - /@aws-sdk/core@3.592.0: + /@aws-sdk/core@3.598.0: resolution: - { integrity: sha512-gLPMXR/HXDP+9gXAt58t7gaMTvRts9i6Q7NMISpkGF54wehskl5WGrbdtHJFylrlJ5BQo3XVY6i661o+EuR1wg== } + { integrity: sha512-HaSjt7puO5Cc7cOlrXFCW0rtA0BM9lvzjl56x0A20Pt+0wxXGeTOZZOkXQIepbrFkV2e/HYukuT9e99vXDm59g== } engines: { node: '>=16.0.0' } dependencies: - '@smithy/core': 2.2.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/signature-v4': 3.0.0 - '@smithy/smithy-client': 3.1.1 - '@smithy/types': 3.0.0 + '@smithy/core': 2.2.3 + '@smithy/protocol-http': 4.0.2 + '@smithy/signature-v4': 3.1.1 + '@smithy/smithy-client': 3.1.4 + '@smithy/types': 3.2.0 fast-xml-parser: 4.2.5 tslib: 2.6.3 dev: true @@ -1053,19 +1101,19 @@ packages: engines: { node: '>=16.0.0' } dependencies: '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.1.0 + '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 tslib: 2.6.3 dev: true - /@aws-sdk/credential-provider-env@3.587.0: + /@aws-sdk/credential-provider-env@3.598.0: resolution: - { integrity: sha512-Hyg/5KFECIk2k5o8wnVEiniV86yVkhn5kzITUydmNGCkXdBFHMHRx6hleQ1bqwJHbBskyu8nbYamzcwymmGwmw== } + { integrity: sha512-vi1khgn7yXzLCcgSIzQrrtd2ilUM0dWodxj3PQ6BLfP0O+q1imO3hG1nq7DVyJtq7rFHs6+9N8G4mYvTkxby2w== } engines: { node: '>=16.0.0' } dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.1.0 - '@smithy/types': 3.0.0 + '@aws-sdk/types': 3.598.0 + '@smithy/property-provider': 3.1.2 + '@smithy/types': 3.2.0 tslib: 2.6.3 dev: true @@ -1077,27 +1125,27 @@ packages: '@aws-sdk/types': 3.577.0 '@smithy/fetch-http-handler': 3.0.1 '@smithy/node-http-handler': 3.0.0 - '@smithy/property-provider': 3.1.0 + '@smithy/property-provider': 3.0.0 '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.1.1 + '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 '@smithy/util-stream': 3.0.1 tslib: 2.6.3 dev: true - /@aws-sdk/credential-provider-http@3.587.0: + /@aws-sdk/credential-provider-http@3.598.0: resolution: - { integrity: sha512-Su1SRWVRCuR1e32oxX3C1V4c5hpPN20WYcRfdcr2wXwHqSvys5DrnmuCC+JoEnS/zt3adUJhPliTqpfKgSdMrA== } + { integrity: sha512-N7cIafi4HVlQvEgvZSo1G4T9qb/JMLGMdBsDCT5XkeJrF0aptQWzTFH0jIdZcLrMYvzPcuEyO3yCBe6cy/ba0g== } engines: { node: '>=16.0.0' } dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/fetch-http-handler': 3.0.1 - '@smithy/node-http-handler': 3.0.0 - '@smithy/property-provider': 3.1.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.1.1 - '@smithy/types': 3.0.0 - '@smithy/util-stream': 3.0.1 + '@aws-sdk/types': 3.598.0 + '@smithy/fetch-http-handler': 3.1.0 + '@smithy/node-http-handler': 3.1.0 + '@smithy/property-provider': 3.1.2 + '@smithy/protocol-http': 4.0.2 + '@smithy/smithy-client': 3.1.4 + '@smithy/types': 3.2.0 + '@smithy/util-stream': 3.0.4 tslib: 2.6.3 dev: true @@ -1114,9 +1162,9 @@ packages: '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 - '@smithy/credential-provider-imds': 3.1.0 - '@smithy/property-provider': 3.1.0 - '@smithy/shared-ini-file-loader': 3.1.0 + '@smithy/credential-provider-imds': 3.0.0 + '@smithy/property-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 '@smithy/types': 3.0.0 tslib: 2.6.3 transitivePeerDependencies: @@ -1124,24 +1172,24 @@ packages: - aws-crt dev: true - /@aws-sdk/credential-provider-ini@3.592.0(@aws-sdk/client-sso-oidc@3.592.0)(@aws-sdk/client-sts@3.592.0): + /@aws-sdk/credential-provider-ini@3.598.0(@aws-sdk/client-sso-oidc@3.600.0)(@aws-sdk/client-sts@3.600.0): resolution: - { integrity: sha512-3kG6ngCIOPbLJZZ3RV+NsU7HVK6vX1+1DrPJKj9fVlPYn7IXsk8NAaUT5885yC7+jKizjv0cWLrLKvAJV5gfUA== } + { integrity: sha512-/ppcIVUbRwDIwJDoYfp90X3+AuJo2mvE52Y1t2VSrvUovYn6N4v95/vXj6LS8CNDhz2jvEJYmu+0cTMHdhI6eA== } engines: { node: '>=16.0.0' } peerDependencies: - '@aws-sdk/client-sts': ^3.592.0 - dependencies: - '@aws-sdk/client-sts': 3.592.0(@aws-sdk/client-sso-oidc@3.592.0) - '@aws-sdk/credential-provider-env': 3.587.0 - '@aws-sdk/credential-provider-http': 3.587.0 - '@aws-sdk/credential-provider-process': 3.587.0 - '@aws-sdk/credential-provider-sso': 3.592.0(@aws-sdk/client-sso-oidc@3.592.0) - '@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.592.0) - '@aws-sdk/types': 3.577.0 - '@smithy/credential-provider-imds': 3.1.0 - '@smithy/property-provider': 3.1.0 - '@smithy/shared-ini-file-loader': 3.1.0 - '@smithy/types': 3.0.0 + '@aws-sdk/client-sts': ^3.598.0 + dependencies: + '@aws-sdk/client-sts': 3.600.0 + '@aws-sdk/credential-provider-env': 3.598.0 + '@aws-sdk/credential-provider-http': 3.598.0 + '@aws-sdk/credential-provider-process': 3.598.0 + '@aws-sdk/credential-provider-sso': 3.598.0(@aws-sdk/client-sso-oidc@3.600.0) + '@aws-sdk/credential-provider-web-identity': 3.598.0(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/types': 3.598.0 + '@smithy/credential-provider-imds': 3.1.2 + '@smithy/property-provider': 3.1.2 + '@smithy/shared-ini-file-loader': 3.1.2 + '@smithy/types': 3.2.0 tslib: 2.6.3 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' @@ -1160,9 +1208,9 @@ packages: '@aws-sdk/credential-provider-sso': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.583.0) '@aws-sdk/types': 3.577.0 - '@smithy/credential-provider-imds': 3.1.0 - '@smithy/property-provider': 3.1.0 - '@smithy/shared-ini-file-loader': 3.1.0 + '@smithy/credential-provider-imds': 3.0.0 + '@smithy/property-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 '@smithy/types': 3.0.0 tslib: 2.6.3 transitivePeerDependencies: @@ -1171,22 +1219,22 @@ packages: - aws-crt dev: true - /@aws-sdk/credential-provider-node@3.592.0(@aws-sdk/client-sso-oidc@3.592.0)(@aws-sdk/client-sts@3.592.0): + /@aws-sdk/credential-provider-node@3.600.0(@aws-sdk/client-sso-oidc@3.600.0)(@aws-sdk/client-sts@3.600.0): resolution: - { integrity: sha512-BguihBGTrEjVBQ07hm+ZsO29eNJaxwBwUZMftgGAm2XcMIEClNPfm5hydxu2BmA4ouIJQJ6nG8pNYghEumM+Aw== } + { integrity: sha512-1pC7MPMYD45J7yFjA90SxpR0yaSvy+yZiq23aXhAPZLYgJBAxHLu0s0mDCk/piWGPh8+UGur5K0bVdx4B1D5hw== } engines: { node: '>=16.0.0' } dependencies: - '@aws-sdk/credential-provider-env': 3.587.0 - '@aws-sdk/credential-provider-http': 3.587.0 - '@aws-sdk/credential-provider-ini': 3.592.0(@aws-sdk/client-sso-oidc@3.592.0)(@aws-sdk/client-sts@3.592.0) - '@aws-sdk/credential-provider-process': 3.587.0 - '@aws-sdk/credential-provider-sso': 3.592.0(@aws-sdk/client-sso-oidc@3.592.0) - '@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.592.0) - '@aws-sdk/types': 3.577.0 - '@smithy/credential-provider-imds': 3.1.0 - '@smithy/property-provider': 3.1.0 - '@smithy/shared-ini-file-loader': 3.1.0 - '@smithy/types': 3.0.0 + '@aws-sdk/credential-provider-env': 3.598.0 + '@aws-sdk/credential-provider-http': 3.598.0 + '@aws-sdk/credential-provider-ini': 3.598.0(@aws-sdk/client-sso-oidc@3.600.0)(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/credential-provider-process': 3.598.0 + '@aws-sdk/credential-provider-sso': 3.598.0(@aws-sdk/client-sso-oidc@3.600.0) + '@aws-sdk/credential-provider-web-identity': 3.598.0(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/types': 3.598.0 + '@smithy/credential-provider-imds': 3.1.2 + '@smithy/property-provider': 3.1.2 + '@smithy/shared-ini-file-loader': 3.1.2 + '@smithy/types': 3.2.0 tslib: 2.6.3 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' @@ -1200,21 +1248,21 @@ packages: engines: { node: '>=16.0.0' } dependencies: '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.1.0 - '@smithy/shared-ini-file-loader': 3.1.0 + '@smithy/property-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 '@smithy/types': 3.0.0 tslib: 2.6.3 dev: true - /@aws-sdk/credential-provider-process@3.587.0: + /@aws-sdk/credential-provider-process@3.598.0: resolution: - { integrity: sha512-V4xT3iCqkF8uL6QC4gqBJg/2asd/damswP1h9HCfqTllmPWzImS+8WD3VjgTLw5b0KbTy+ZdUhKc0wDnyzkzxg== } + { integrity: sha512-rM707XbLW8huMk722AgjVyxu2tMZee++fNA8TJVNgs1Ma02Wx6bBrfIvlyK0rCcIRb0WdQYP6fe3Xhiu4e8IBA== } engines: { node: '>=16.0.0' } dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.1.0 - '@smithy/shared-ini-file-loader': 3.1.0 - '@smithy/types': 3.0.0 + '@aws-sdk/types': 3.598.0 + '@smithy/property-provider': 3.1.2 + '@smithy/shared-ini-file-loader': 3.1.2 + '@smithy/types': 3.2.0 tslib: 2.6.3 dev: true @@ -1226,8 +1274,8 @@ packages: '@aws-sdk/client-sso': 3.583.0 '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.1.0 - '@smithy/shared-ini-file-loader': 3.1.0 + '@smithy/property-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 '@smithy/types': 3.0.0 tslib: 2.6.3 transitivePeerDependencies: @@ -1235,17 +1283,17 @@ packages: - aws-crt dev: true - /@aws-sdk/credential-provider-sso@3.592.0(@aws-sdk/client-sso-oidc@3.592.0): + /@aws-sdk/credential-provider-sso@3.598.0(@aws-sdk/client-sso-oidc@3.600.0): resolution: - { integrity: sha512-fYFzAdDHKHvhtufPPtrLdSv8lO6GuW3em6n3erM5uFdpGytNpjXvr3XGokIsuXcNkETAY/Xihg+G9ksNE8WJxQ== } + { integrity: sha512-5InwUmrAuqQdOOgxTccRayMMkSmekdLk6s+az9tmikq0QFAHUCtofI+/fllMXSR9iL6JbGYi1940+EUmS4pHJA== } engines: { node: '>=16.0.0' } dependencies: - '@aws-sdk/client-sso': 3.592.0 - '@aws-sdk/token-providers': 3.587.0(@aws-sdk/client-sso-oidc@3.592.0) - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.1.0 - '@smithy/shared-ini-file-loader': 3.1.0 - '@smithy/types': 3.0.0 + '@aws-sdk/client-sso': 3.598.0 + '@aws-sdk/token-providers': 3.598.0(@aws-sdk/client-sso-oidc@3.600.0) + '@aws-sdk/types': 3.598.0 + '@smithy/property-provider': 3.1.2 + '@smithy/shared-ini-file-loader': 3.1.2 + '@smithy/types': 3.2.0 tslib: 2.6.3 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' @@ -1261,22 +1309,22 @@ packages: dependencies: '@aws-sdk/client-sts': 3.583.0(@aws-sdk/client-sso-oidc@3.583.0) '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.1.0 + '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 tslib: 2.6.3 dev: true - /@aws-sdk/credential-provider-web-identity@3.587.0(@aws-sdk/client-sts@3.592.0): + /@aws-sdk/credential-provider-web-identity@3.598.0(@aws-sdk/client-sts@3.600.0): resolution: - { integrity: sha512-XqIx/I2PG7kyuw3WjAP9wKlxy8IvFJwB8asOFT1xPFoVfZYKIogjG9oLP5YiRtfvDkWIztHmg5MlVv3HdJDGRw== } + { integrity: sha512-GV5GdiMbz5Tz9JO4NJtRoFXjW0GPEujA0j+5J/B723rTN+REHthJu48HdBKouHGhdzkDWkkh1bu52V02Wprw8w== } engines: { node: '>=16.0.0' } peerDependencies: - '@aws-sdk/client-sts': ^3.587.0 + '@aws-sdk/client-sts': ^3.598.0 dependencies: - '@aws-sdk/client-sts': 3.592.0(@aws-sdk/client-sso-oidc@3.592.0) - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.1.0 - '@smithy/types': 3.0.0 + '@aws-sdk/client-sts': 3.600.0 + '@aws-sdk/types': 3.598.0 + '@smithy/property-provider': 3.1.2 + '@smithy/types': 3.2.0 tslib: 2.6.3 dev: true @@ -1287,7 +1335,7 @@ packages: dependencies: '@aws-sdk/types': 3.577.0 '@aws-sdk/util-arn-parser': 3.568.0 - '@smithy/node-config-provider': 3.1.0 + '@smithy/node-config-provider': 3.0.0 '@smithy/protocol-http': 4.0.0 '@smithy/types': 3.0.0 '@smithy/util-config-provider': 3.0.0 @@ -1331,6 +1379,17 @@ packages: tslib: 2.6.3 dev: true + /@aws-sdk/middleware-host-header@3.598.0: + resolution: + { integrity: sha512-WiaG059YBQwQraNejLIi0gMNkX7dfPZ8hDIhvMr5aVPRbaHH8AYF3iNSsXYCHvA2Cfa1O9haYXsuMF9flXnCmA== } + engines: { node: '>=16.0.0' } + dependencies: + '@aws-sdk/types': 3.598.0 + '@smithy/protocol-http': 4.0.2 + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@aws-sdk/middleware-location-constraint@3.577.0: resolution: { integrity: sha512-DKPTD2D2s+t2QUo/IXYtVa/6Un8GZ+phSTBkyBNx2kfZz4Kwavhl/JJzSqTV3GfCXkVdFu7CrjoX7BZ6qWeTUA== } @@ -1351,6 +1410,16 @@ packages: tslib: 2.6.3 dev: true + /@aws-sdk/middleware-logger@3.598.0: + resolution: + { integrity: sha512-bxBjf/VYiu3zfu8SYM2S9dQQc3tz5uBAOcPz/Bt8DyyK3GgOpjhschH/2XuUErsoUO1gDJqZSdGOmuHGZQn00Q== } + engines: { node: '>=16.0.0' } + dependencies: + '@aws-sdk/types': 3.598.0 + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@aws-sdk/middleware-recursion-detection@3.577.0: resolution: { integrity: sha512-pn3ZVEd2iobKJlR3H+bDilHjgRnNrQ6HMmK9ZzZw89Ckn3Dcbv48xOv4RJvu0aU8SDLl/SNCxppKjeLDTPGBNA== } @@ -1362,6 +1431,17 @@ packages: tslib: 2.6.3 dev: true + /@aws-sdk/middleware-recursion-detection@3.598.0: + resolution: + { integrity: sha512-vjT9BeFY9FeN0f8hm2l6F53tI0N5bUq6RcDkQXKNabXBnQxKptJRad6oP2X5y3FoVfBLOuDkQgiC2940GIPxtQ== } + engines: { node: '>=16.0.0' } + dependencies: + '@aws-sdk/types': 3.598.0 + '@smithy/protocol-http': 4.0.2 + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@aws-sdk/middleware-sdk-s3@3.582.0: resolution: { integrity: sha512-PJqQpLoLaZPRI4L/XZUeHkd9UVK8VAr9R38wv0osGeMTvzD9iwzzk0I2TtBqFda/5xEB1YgVYZwyqvmStXmttg== } @@ -1369,10 +1449,10 @@ packages: dependencies: '@aws-sdk/types': 3.577.0 '@aws-sdk/util-arn-parser': 3.568.0 - '@smithy/node-config-provider': 3.1.0 + '@smithy/node-config-provider': 3.0.0 '@smithy/protocol-http': 4.0.0 '@smithy/signature-v4': 3.0.0 - '@smithy/smithy-client': 3.1.1 + '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 '@smithy/util-config-provider': 3.0.0 tslib: 2.6.3 @@ -1384,7 +1464,7 @@ packages: engines: { node: '>=16.0.0' } dependencies: '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.1.0 + '@smithy/property-provider': 3.0.0 '@smithy/protocol-http': 4.0.0 '@smithy/signature-v4': 3.0.0 '@smithy/types': 3.0.0 @@ -1414,15 +1494,15 @@ packages: tslib: 2.6.3 dev: true - /@aws-sdk/middleware-user-agent@3.587.0: + /@aws-sdk/middleware-user-agent@3.598.0: resolution: - { integrity: sha512-SyDomN+IOrygLucziG7/nOHkjUXES5oH5T7p8AboO8oakMQJdnudNXiYWTicQWO52R51U6CR27rcMPTGeMedYA== } + { integrity: sha512-4tjESlHG5B5MdjUaLK7tQs/miUtHbb6deauQx8ryqSBYOhfHVgb1ZnzvQR0bTrhpqUg0WlybSkDaZAICf9xctg== } engines: { node: '>=16.0.0' } dependencies: - '@aws-sdk/types': 3.577.0 - '@aws-sdk/util-endpoints': 3.587.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/types': 3.0.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@smithy/protocol-http': 4.0.2 + '@smithy/types': 3.2.0 tslib: 2.6.3 dev: true @@ -1432,23 +1512,23 @@ packages: engines: { node: '>=16.0.0' } dependencies: '@aws-sdk/types': 3.577.0 - '@smithy/node-config-provider': 3.1.0 + '@smithy/node-config-provider': 3.0.0 '@smithy/types': 3.0.0 '@smithy/util-config-provider': 3.0.0 '@smithy/util-middleware': 3.0.0 tslib: 2.6.3 dev: true - /@aws-sdk/region-config-resolver@3.587.0: + /@aws-sdk/region-config-resolver@3.598.0: resolution: - { integrity: sha512-93I7IPZtulZQoRK+O20IJ4a1syWwYPzoO2gc3v+/GNZflZPV3QJXuVbIm0pxBsu0n/mzKGUKqSOLPIaN098HcQ== } + { integrity: sha512-oYXhmTokSav4ytmWleCr3rs/1nyvZW/S0tdi6X7u+dLNL5Jee+uMxWGzgOrWK6wrQOzucLVjS4E/wA11Kv2GTw== } engines: { node: '>=16.0.0' } dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/node-config-provider': 3.1.0 - '@smithy/types': 3.0.0 + '@aws-sdk/types': 3.598.0 + '@smithy/node-config-provider': 3.1.2 + '@smithy/types': 3.2.0 '@smithy/util-config-provider': 3.0.0 - '@smithy/util-middleware': 3.0.0 + '@smithy/util-middleware': 3.0.2 tslib: 2.6.3 dev: true @@ -1474,24 +1554,24 @@ packages: dependencies: '@aws-sdk/client-sso-oidc': 3.583.0 '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.1.0 - '@smithy/shared-ini-file-loader': 3.1.0 + '@smithy/property-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 '@smithy/types': 3.0.0 tslib: 2.6.3 dev: true - /@aws-sdk/token-providers@3.587.0(@aws-sdk/client-sso-oidc@3.592.0): + /@aws-sdk/token-providers@3.598.0(@aws-sdk/client-sso-oidc@3.600.0): resolution: - { integrity: sha512-ULqhbnLy1hmJNRcukANBWJmum3BbjXnurLPSFXoGdV0llXYlG55SzIla2VYqdveQEEjmsBuTZdFvXAtNpmS5Zg== } + { integrity: sha512-TKY1EVdHVBnZqpyxyTHdpZpa1tUpb6nxVeRNn1zWG8QB5MvH4ALLd/jR+gtmWDNQbIG4cVuBOZFVL8hIYicKTA== } engines: { node: '>=16.0.0' } peerDependencies: - '@aws-sdk/client-sso-oidc': ^3.587.0 + '@aws-sdk/client-sso-oidc': ^3.598.0 dependencies: - '@aws-sdk/client-sso-oidc': 3.592.0 - '@aws-sdk/types': 3.577.0 - '@smithy/property-provider': 3.1.0 - '@smithy/shared-ini-file-loader': 3.1.0 - '@smithy/types': 3.0.0 + '@aws-sdk/client-sso-oidc': 3.600.0(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/types': 3.598.0 + '@smithy/property-provider': 3.1.2 + '@smithy/shared-ini-file-loader': 3.1.2 + '@smithy/types': 3.2.0 tslib: 2.6.3 dev: true @@ -1504,6 +1584,15 @@ packages: tslib: 2.6.3 dev: true + /@aws-sdk/types@3.598.0: + resolution: + { integrity: sha512-742uRl6z7u0LFmZwDrFP6r1wlZcgVPw+/TilluDJmCAR8BgRw3IR+743kUXKBGd8QZDRW2n6v/PYsi/AWCDDMQ== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@aws-sdk/util-arn-parser@3.568.0: resolution: { integrity: sha512-XUKJWWo+KOB7fbnPP0+g/o5Ulku/X53t7i/h+sPHr5xxYTJJ9CYnbToo95mzxe7xWvkLrsNtJ8L+MnNn9INs2w== } @@ -1519,18 +1608,18 @@ packages: dependencies: '@aws-sdk/types': 3.577.0 '@smithy/types': 3.0.0 - '@smithy/util-endpoints': 2.0.1 + '@smithy/util-endpoints': 2.0.0 tslib: 2.6.3 dev: true - /@aws-sdk/util-endpoints@3.587.0: + /@aws-sdk/util-endpoints@3.598.0: resolution: - { integrity: sha512-8I1HG6Em8wQWqKcRW6m358mqebRVNpL8XrrEoT4In7xqkKkmYtHRNVYP6lcmiQh5pZ/c/FXu8dSchuFIWyEtqQ== } + { integrity: sha512-Qo9UoiVVZxcOEdiOMZg3xb1mzkTxrhd4qSlg5QQrfWPJVx/QOg+Iy0NtGxPtHtVZNHZxohYwDwV/tfsnDSE2gQ== } engines: { node: '>=16.0.0' } dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/types': 3.0.0 - '@smithy/util-endpoints': 2.0.1 + '@aws-sdk/types': 3.598.0 + '@smithy/types': 3.2.0 + '@smithy/util-endpoints': 2.0.3 tslib: 2.6.3 dev: true @@ -1552,6 +1641,16 @@ packages: tslib: 2.6.3 dev: true + /@aws-sdk/util-user-agent-browser@3.598.0: + resolution: + { integrity: sha512-36Sxo6F+ykElaL1mWzWjlg+1epMpSe8obwhCN1yGE7Js9ywy5U6k6l+A3q3YM9YRbm740sNxncbwLklMvuhTKw== } + dependencies: + '@aws-sdk/types': 3.598.0 + '@smithy/types': 3.2.0 + bowser: 2.11.0 + tslib: 2.6.3 + dev: true + /@aws-sdk/util-user-agent-node@3.577.0: resolution: { integrity: sha512-XqvtFjbSMtycZTWVwDe8DRWovuoMbA54nhUoZwVU6rW9OSD6NZWGR512BUGHFaWzW0Wg8++Dj10FrKTG2XtqfA== } @@ -1563,14 +1662,14 @@ packages: optional: true dependencies: '@aws-sdk/types': 3.577.0 - '@smithy/node-config-provider': 3.1.0 + '@smithy/node-config-provider': 3.0.0 '@smithy/types': 3.0.0 tslib: 2.6.3 dev: true - /@aws-sdk/util-user-agent-node@3.587.0: + /@aws-sdk/util-user-agent-node@3.598.0: resolution: - { integrity: sha512-Pnl+DUe/bvnbEEDHP3iVJrOtE3HbFJBPgsD6vJ+ml/+IYk1Eq49jEG+EHZdNTPz3SDG0kbp2+7u41MKYJHR/iQ== } + { integrity: sha512-oyWGcOlfTdzkC6SVplyr0AGh54IMrDxbhg5RxJ5P+V4BKfcDoDcZV9xenUk9NsOi9MuUjxMumb9UJGkDhM1m0A== } engines: { node: '>=16.0.0' } peerDependencies: aws-crt: '>=1.0.0' @@ -1578,9 +1677,9 @@ packages: aws-crt: optional: true dependencies: - '@aws-sdk/types': 3.577.0 - '@smithy/node-config-provider': 3.1.0 - '@smithy/types': 3.0.0 + '@aws-sdk/types': 3.598.0 + '@smithy/node-config-provider': 3.1.2 + '@smithy/types': 3.2.0 tslib: 2.6.3 dev: true @@ -1600,13 +1699,22 @@ packages: tslib: 2.6.3 dev: true + /@aws-sdk/xml-builder@3.598.0: + resolution: + { integrity: sha512-ZIa2RK7CHFTZ4gwK77WRtsZ6vF7xwRXxJ8KQIxK2duhoTVcn0xYxpFLdW9WZZZvdP9GIF3Loqvf8DRdeU5Jc7Q== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@babel/code-frame@7.24.6: resolution: { integrity: sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA== } engines: { node: '>=6.9.0' } dependencies: '@babel/highlight': 7.24.6 - picocolors: 1.0.0 + picocolors: 1.0.1 /@babel/code-frame@7.24.7: resolution: @@ -1637,7 +1745,7 @@ packages: '@babel/traverse': 7.24.7 '@babel/types': 7.24.7 convert-source-map: 2.0.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -1748,7 +1856,7 @@ packages: '@babel/core': 7.24.7 '@babel/helper-compilation-targets': 7.24.7 '@babel/helper-plugin-utils': 7.24.7 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.22.6 transitivePeerDependencies: @@ -3031,7 +3139,7 @@ packages: '@babel/helper-split-export-declaration': 7.24.7 '@babel/parser': 7.24.7 '@babel/types': 7.24.7 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -3340,9 +3448,9 @@ packages: prettier: 2.8.8 dev: true - /@cloudflare/workers-types@4.20240614.0: + /@cloudflare/workers-types@4.20240620.0: resolution: - { integrity: sha512-fnV3uXD1Hpq5EWnY7XYb+smPcjzIoUFiZpTSV/Tk8qKL3H+w6IqcngZwXQBZ/2U/DwYkDilXHW3FfPhnyD7FZA== } + { integrity: sha512-CQD8YS6evRob7LChvIX3gE3zYo0KVgaLDOu1SwNP1BVIS2Sa0b+FC8S1e1hhrNN8/E4chYlVN+FDAgA4KRDUEQ== } dev: false /@cspotcode/source-map-support@0.8.1: @@ -4090,7 +4198,7 @@ packages: engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } dependencies: '@eslint/object-schema': 2.1.4 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -4102,7 +4210,7 @@ packages: engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } dependencies: ajv: 6.12.6 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) espree: 10.0.1 globals: 14.0.0 ignore: 5.3.1 @@ -4152,7 +4260,7 @@ packages: engines: { node: ^8.13.0 || >=10.10.0 } dependencies: '@grpc/proto-loader': 0.7.10 - '@types/node': 20.14.2 + '@types/node': 20.14.7 /@grpc/proto-loader@0.7.10: resolution: @@ -4182,10 +4290,10 @@ packages: '@opentelemetry/exporter-metrics-otlp-proto': 0.36.1(@opentelemetry/api@1.9.0) '@opentelemetry/exporter-trace-otlp-grpc': 0.36.1(@opentelemetry/api@1.9.0) '@opentelemetry/exporter-trace-otlp-proto': 0.36.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.25.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-metrics': 1.18.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-node': 0.36.1(@opentelemetry/api@1.9.0)(supports-color@9.4.0) - '@opentelemetry/sdk-trace-base': 1.25.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) axios: 1.5.0 transitivePeerDependencies: - debug @@ -4215,6 +4323,14 @@ packages: { integrity: sha512-tWZNBIS1CoekcwlMuyG2mr0a1Wo5lb5lEHwwWvZo+5GLgr3e9LLDTtmgtCWEwBpXMkxn9D+2W9j2FY6eZQq0tA== } dev: false + /@inquirer/confirm@3.1.10: + resolution: + { integrity: sha512-/aAHu83Njy6yf44T+ZrRPUkMcUqprrOiIKsyMvf9jOV+vF5BNb2ja1aLP33MK36W8eaf91MTL/mU/e6METuENg== } + engines: { node: '>=18' } + dependencies: + '@inquirer/core': 8.2.3 + '@inquirer/type': 1.3.3 + /@inquirer/confirm@3.1.8: resolution: { integrity: sha512-f3INZ+ca4dQdn+MQiq1yP/mOIR/Oc8BLRYuDh6ciToWd6z4W8yArfzjBCMQ0BPY8PcJKwZxGIt8Z6yNT32eSTw== } @@ -4224,14 +4340,6 @@ packages: '@inquirer/type': 1.3.2 dev: true - /@inquirer/confirm@3.1.9: - resolution: - { integrity: sha512-UF09aejxCi4Xqm6N/jJAiFXArXfi9al52AFaSD+2uIHnhZGtd1d6lIGTRMPouVSJxbGEi+HkOWSYaiEY/+szUw== } - engines: { node: '>=18' } - dependencies: - '@inquirer/core': 8.2.2 - '@inquirer/type': 1.3.3 - /@inquirer/core@8.2.1: resolution: { integrity: sha512-TIcuQMn2qrtyYe0j136UpHeYpk7AcR/trKeT/7YY0vRgcS9YSfJuQ2+PudPhSofLLsHNnRYAHScQCcVZrJkMqA== } @@ -4240,7 +4348,7 @@ packages: '@inquirer/figures': 1.0.2 '@inquirer/type': 1.3.2 '@types/mute-stream': 0.0.4 - '@types/node': 20.14.2 + '@types/node': 20.14.7 '@types/wrap-ansi': 3.0.0 ansi-escapes: 4.3.2 chalk: 4.1.2 @@ -4252,15 +4360,15 @@ packages: wrap-ansi: 6.2.0 dev: true - /@inquirer/core@8.2.2: + /@inquirer/core@8.2.3: resolution: - { integrity: sha512-K8SuNX45jEFlX3EBJpu9B+S2TISzMPGXZIuJ9ME924SqbdW6Pt6fIkKvXg7mOEOKJ4WxpQsxj0UTfcL/A434Ww== } + { integrity: sha512-WrpDVPAaxJQjHid3Ra4FhUO70YBzkHSYVyW5X48L5zHYdudoPISJqTRRWSeamHfaXda7PNNaC5Py5MEo7QwBNA== } engines: { node: '>=18' } dependencies: '@inquirer/figures': 1.0.3 '@inquirer/type': 1.3.3 '@types/mute-stream': 0.0.4 - '@types/node': 20.14.2 + '@types/node': 20.14.7 '@types/wrap-ansi': 3.0.0 ansi-escapes: 4.3.2 chalk: 4.1.2 @@ -4282,21 +4390,21 @@ packages: { integrity: sha512-ErXXzENMH5pJt5/ssXV0DfWUZqly8nGzf0UcBV9xTnP+KyffE2mqyxIMBrZ8ijQck2nU0TQm40EQB53YreyWHw== } engines: { node: '>=18' } - /@inquirer/input@2.1.9: + /@inquirer/input@2.1.10: resolution: - { integrity: sha512-1xTCHmIe48x9CG1+8glAHrVVdH+QfYhzgBUbgyoVpp5NovnXgRcjSn/SNulepxf9Ol8HDq3gzw3ZCAUr+h1Eyg== } + { integrity: sha512-KEnho7O0YBj+peA40ZGOuBYf00EQnYbQlPsORgZYdjdUVUrMqQPW3qIvRNJIq+lYlc9RZrfHeMoAv+tWAoZFQg== } engines: { node: '>=18' } dependencies: - '@inquirer/core': 8.2.2 + '@inquirer/core': 8.2.3 '@inquirer/type': 1.3.3 dev: true - /@inquirer/select@2.3.5: + /@inquirer/select@2.3.6: resolution: - { integrity: sha512-IyBj8oEtmdF2Gx4FJTPtEya37MD6s0KATKsHqgmls0lK7EQbhYSq9GQlcFq6cBsYe/cgQ0Fg2cCqYYPi/d/fxQ== } + { integrity: sha512-eLqlZXre69Jenmar5s+3018xF3lpaGfxVZLHkCzkrhtuTuFjpYtb0YpiYeZNKZm9pa+ih3s9acN/zRt+dDh+qA== } engines: { node: '>=18' } dependencies: - '@inquirer/core': 8.2.2 + '@inquirer/core': 8.2.3 '@inquirer/figures': 1.0.3 '@inquirer/type': 1.3.3 ansi-escapes: 4.3.2 @@ -4342,7 +4450,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.14.2 + '@types/node': 20.14.7 '@types/yargs': 16.0.6 chalk: 4.1.2 dev: false @@ -4449,7 +4557,7 @@ packages: { integrity: sha512-4wMPu9iN3/HL97QblBsBay3E1etIciR84izI3U+4iALY+JHCrI+a2jO0qbAZ/nxKoegypYEaiiqWXylm+/zfrw== } dev: false - /@netlify/build@29.20.6(@types/node@20.14.2): + /@netlify/build@29.20.6(@types/node@20.14.7): resolution: { integrity: sha512-AynL2Sn1bKMYzB4e05CsDObQYDVSN11f1rJCO/41iafmxhXXQWIYR3Q7qZeK30C4uHSk4WjhD/K18PBgQDsjhw== } engines: { node: ^14.16.0 || >=16.0.0 } @@ -4506,7 +4614,7 @@ packages: strip-ansi: 7.1.0 supports-color: 9.4.0 terminal-link: 3.0.0 - ts-node: 10.9.2(@types/node@20.14.2)(typescript@5.4.5) + ts-node: 10.9.2(@types/node@20.14.7)(typescript@5.4.5) typescript: 5.4.5 uuid: 9.0.1 yargs: 17.7.2 @@ -5020,7 +5128,7 @@ packages: clean-stack: 3.0.1 cli-progress: 3.12.0 color: 4.2.3 - debug: 4.3.5(supports-color@8.1.1) + debug: 4.3.4(supports-color@8.1.1) ejs: 3.1.10 get-package-type: 0.1.0 globby: 11.1.0 @@ -5077,7 +5185,7 @@ packages: { integrity: sha512-C3YgT46dQpVs0DkXECTVrlg8KeOzLAOXFpmCYMPQQU3siptliep2eESjXrFm9VL+jZijGJjyckwQgn/X5zq1LQ== } engines: { node: '>=18.0.0' } dependencies: - '@inquirer/confirm': 3.1.9 + '@inquirer/confirm': 3.1.10 '@oclif/core': 4.0.6 ansis: 3.2.0 fast-levenshtein: 3.0.0 @@ -5089,7 +5197,7 @@ packages: dependencies: '@oclif/core': 4.0.6 ansis: 3.2.0 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) npm: 10.8.1 npm-package-arg: 11.0.2 npm-run-path: 5.3.0 @@ -5109,7 +5217,7 @@ packages: dependencies: '@oclif/core': 3.26.6 chalk: 5.3.0 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) http-call: 5.3.0 lodash: 4.17.21 transitivePeerDependencies: @@ -5131,7 +5239,7 @@ packages: '@octokit/graphql': 8.1.1 '@octokit/request': 9.1.1 '@octokit/request-error': 6.1.1 - '@octokit/types': 13.4.1 + '@octokit/types': 13.5.0 before-after-hook: 3.0.2 universal-user-agent: 7.0.2 dev: false @@ -5141,7 +5249,7 @@ packages: { integrity: sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q== } engines: { node: '>= 18' } dependencies: - '@octokit/types': 13.4.1 + '@octokit/types': 13.5.0 universal-user-agent: 7.0.2 dev: false @@ -5151,13 +5259,13 @@ packages: engines: { node: '>= 18' } dependencies: '@octokit/request': 9.1.1 - '@octokit/types': 13.4.1 + '@octokit/types': 13.5.0 universal-user-agent: 7.0.2 dev: false - /@octokit/openapi-types@22.1.0: + /@octokit/openapi-types@22.2.0: resolution: - { integrity: sha512-pGUdSP+eEPfZiQHNkZI0U01HLipxncisdJQB4G//OAmfeO8sqTQ9KRa0KF03TUPCziNsoXUrTg4B2Q1EX++T0Q== } + { integrity: sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg== } dev: false /@octokit/request-error@6.1.1: @@ -5165,7 +5273,7 @@ packages: { integrity: sha512-1mw1gqT3fR/WFvnoVpY/zUM2o/XkMs/2AszUUG9I69xn0JFLv6PGkPhNk5lbfvROs79wiS0bqiJNxfCZcRJJdg== } engines: { node: '>= 18' } dependencies: - '@octokit/types': 13.4.1 + '@octokit/types': 13.5.0 dev: false /@octokit/request@9.1.1: @@ -5175,15 +5283,15 @@ packages: dependencies: '@octokit/endpoint': 10.1.1 '@octokit/request-error': 6.1.1 - '@octokit/types': 13.4.1 + '@octokit/types': 13.5.0 universal-user-agent: 7.0.2 dev: false - /@octokit/types@13.4.1: + /@octokit/types@13.5.0: resolution: - { integrity: sha512-Y73oOAzRBAUzR/iRAbGULzpNkX8vaxKCqEtg6K74Ff3w9f5apFnWtE/2nade7dMWWW3bS5Kkd6DJS4HF04xreg== } + { integrity: sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ== } dependencies: - '@octokit/openapi-types': 22.1.0 + '@octokit/openapi-types': 22.2.0 dev: false /@open-draft/deferred-promise@2.2.0: @@ -5254,9 +5362,9 @@ packages: typescript: 4.8.2 dev: true - /@opentelemetry/api-logs@0.52.0: + /@opentelemetry/api-logs@0.52.1: resolution: - { integrity: sha512-HxjD7xH9iAE4OyhNaaSec65i1H6QZYBWSwWkowFfsc5YAcDvJG30/J1sRKXEQqdmUcKTXEAnA66UciqZha/4+Q== } + { integrity: sha512-qnSqB2DQ9TPP96dl8cDubDvrUyWc0/sK81xHTK8eSUspzDM3bsewX903qclQFvVhgStjRWdC5bLb3kQqMkfV5A== } engines: { node: '>=14' } dependencies: '@opentelemetry/api': 1.9.0 @@ -5277,9 +5385,9 @@ packages: '@opentelemetry/api': 1.9.0 dev: false - /@opentelemetry/context-async-hooks@1.25.0(@opentelemetry/api@1.9.0): + /@opentelemetry/context-async-hooks@1.25.1(@opentelemetry/api@1.9.0): resolution: - { integrity: sha512-sBW313mnMyFg0cp/40BRzrZBWG+581s2j5gIsa5fgGadswyILk4mNFATsqrCOpAx945RDuZ2B7ThQLgor9OpfA== } + { integrity: sha512-UW/ge9zjvAEmRWVapOP0qyCvPulWU6cQxGxDbWEFfGOj1VBBZAuOqTo3X6yWmDTD3Xe15ysCZChHncr2xFMIfQ== } engines: { node: '>=14' } peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -5309,15 +5417,15 @@ packages: '@opentelemetry/semantic-conventions': 1.18.1 dev: false - /@opentelemetry/core@1.25.0(@opentelemetry/api@1.9.0): + /@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0): resolution: - { integrity: sha512-n0B3s8rrqGrasTgNkXLKXzN0fXo+6IYP7M5b7AMsrZM33f/y6DS6kJ0Btd7SespASWq8bgL3taLo0oe0vB52IQ== } + { integrity: sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ== } engines: { node: '>=14' } peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/semantic-conventions': 1.25.0 + '@opentelemetry/semantic-conventions': 1.25.1 /@opentelemetry/exporter-jaeger@1.10.1(@opentelemetry/api@1.9.0): resolution: @@ -5398,20 +5506,20 @@ packages: '@opentelemetry/sdk-trace-base': 1.10.1(@opentelemetry/api@1.9.0) dev: false - /@opentelemetry/exporter-trace-otlp-grpc@0.52.0(@opentelemetry/api@1.9.0): + /@opentelemetry/exporter-trace-otlp-grpc@0.52.1(@opentelemetry/api@1.9.0): resolution: - { integrity: sha512-Ln3HU54/ytTeEMrDGNDj01357YV8Kk9PkGDHvBRo1n7bWhwZoTEnX/cTuXLYOiygBIJJjCCM+VMfWCnvtFl4Kw== } + { integrity: sha512-pVkSH20crBwMTqB3nIN4jpQKUEoB0Z94drIHpYyEqs7UBr+I0cpYyOR3bqjA/UasQUMROb3GX8ZX4/9cVRqGBQ== } engines: { node: '>=14' } peerDependencies: '@opentelemetry/api': ^1.0.0 dependencies: '@grpc/grpc-js': 1.9.3 '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-grpc-exporter-base': 0.52.0(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.52.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.25.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-grpc-exporter-base': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) dev: true /@opentelemetry/exporter-trace-otlp-http@0.36.1(@opentelemetry/api@1.9.0): @@ -5474,17 +5582,17 @@ packages: - supports-color dev: false - /@opentelemetry/instrumentation@0.52.0(@opentelemetry/api@1.9.0): + /@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0): resolution: - { integrity: sha512-LPwSIrw+60cheWaXsfGL8stBap/AppKQJFE+qqRvzYrgttXFH2ofoIMxWadeqPTq4BYOXM/C7Bdh/T+B60xnlQ== } + { integrity: sha512-uXJbYU/5/MBHjMp1FqrILLRuiJCs3Ofk0MeRDk8g1S1gD47U8X3JnSwcMO1rtRo1x1a7zKaQHaoYu49p/4eSKw== } engines: { node: '>=14' } peerDependencies: '@opentelemetry/api': ^1.3.0 dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.52.0 + '@opentelemetry/api-logs': 0.52.1 '@types/shimmer': 1.0.3 - import-in-the-middle: 1.8.0 + import-in-the-middle: 1.8.1 require-in-the-middle: 7.2.0 semver: 7.6.2 shimmer: 1.2.1 @@ -5503,16 +5611,16 @@ packages: '@opentelemetry/core': 1.10.1(@opentelemetry/api@1.9.0) dev: false - /@opentelemetry/otlp-exporter-base@0.52.0(@opentelemetry/api@1.9.0): + /@opentelemetry/otlp-exporter-base@0.52.1(@opentelemetry/api@1.9.0): resolution: - { integrity: sha512-rlyg5UKW9yMTNMUxYYib9XxEE/krpH7Q6mIuJNOBMbjLwmqe1WQ2MNKNzobVZTKop/FX4CvyNN3wUEl/6gnvfw== } + { integrity: sha512-z175NXOtX5ihdlshtYBe5RpGeBoTXVCKPPLiQlD6FHvpM4Ch+p2B0yWKYSrBfLH24H9zjJiBdTrtD+hLlfnXEQ== } engines: { node: '>=14' } peerDependencies: '@opentelemetry/api': ^1.0.0 dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.52.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.52.1(@opentelemetry/api@1.9.0) dev: true /@opentelemetry/otlp-grpc-exporter-base@0.36.1(@opentelemetry/api@1.9.0): @@ -5529,18 +5637,18 @@ packages: '@opentelemetry/otlp-exporter-base': 0.36.1(@opentelemetry/api@1.9.0) dev: false - /@opentelemetry/otlp-grpc-exporter-base@0.52.0(@opentelemetry/api@1.9.0): + /@opentelemetry/otlp-grpc-exporter-base@0.52.1(@opentelemetry/api@1.9.0): resolution: - { integrity: sha512-iVq3wCElOoKUkxBOuvV8cfaELG8WO/zfLWIZil6iw/6hj6rktLodnJ7kVOneVmLki7Po1BjE1K7JOp2G3UPgYg== } + { integrity: sha512-zo/YrSDmKMjG+vPeA9aBBrsQM9Q/f2zo6N04WMB3yNldJRsgpRBeLLwvAt/Ba7dpehDLOEFBd1i2JCoaFtpCoQ== } engines: { node: '>=14' } peerDependencies: '@opentelemetry/api': ^1.0.0 dependencies: '@grpc/grpc-js': 1.9.3 '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.52.0(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.52.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.52.1(@opentelemetry/api@1.9.0) dev: true /@opentelemetry/otlp-proto-exporter-base@0.36.1(@opentelemetry/api@1.9.0): @@ -5570,21 +5678,21 @@ packages: '@opentelemetry/sdk-trace-base': 1.10.1(@opentelemetry/api@1.9.0) dev: false - /@opentelemetry/otlp-transformer@0.52.0(@opentelemetry/api@1.9.0): + /@opentelemetry/otlp-transformer@0.52.1(@opentelemetry/api@1.9.0): resolution: - { integrity: sha512-40acy3JxCAqQYcYepypF/64GVB8jerC6Oiz1HRUXxiSTVwg+ud7UtywfOkPRpc9bjHiyJouWxTjiUPQ9VBMKbg== } + { integrity: sha512-I88uCZSZZtVa0XniRqQWKbjAUm73I8tpEy/uJYPPYw5d7BRdVk0RfTBQw8kSUl01oVWEuqxLDa802222MYyWHg== } engines: { node: '>=14' } peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.52.0 - '@opentelemetry/core': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-logs': 0.52.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.25.0(@opentelemetry/api@1.9.0) - protobufjs: 7.3.0 + '@opentelemetry/api-logs': 0.52.1 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) + protobufjs: 7.3.2 dev: true /@opentelemetry/propagator-b3@1.10.1(@opentelemetry/api@1.9.0): @@ -5598,15 +5706,15 @@ packages: '@opentelemetry/core': 1.10.1(@opentelemetry/api@1.9.0) dev: false - /@opentelemetry/propagator-b3@1.25.0(@opentelemetry/api@1.9.0): + /@opentelemetry/propagator-b3@1.25.1(@opentelemetry/api@1.9.0): resolution: - { integrity: sha512-/A+1Tbnf0uwnP51OkoaQlrb9YILdHsoqIISna1MNXpZRzf42xm6LVLb49i+m/zlJoW1e8P4ekcrditR5pfmwog== } + { integrity: sha512-p6HFscpjrv7//kE+7L+3Vn00VEDUJB0n6ZrjkTYHrJ58QZ8B3ajSJhRbCcY6guQ3PDjTbxWklyvIN2ojVbIb1A== } engines: { node: '>=14' } peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.25.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) dev: true /@opentelemetry/propagator-jaeger@1.10.1(@opentelemetry/api@1.9.0): @@ -5620,15 +5728,15 @@ packages: '@opentelemetry/core': 1.10.1(@opentelemetry/api@1.9.0) dev: false - /@opentelemetry/propagator-jaeger@1.25.0(@opentelemetry/api@1.9.0): + /@opentelemetry/propagator-jaeger@1.25.1(@opentelemetry/api@1.9.0): resolution: - { integrity: sha512-uwA5xqaPISXeX+YutqbjmzENnCGCvrIXlqIXP5gRoA5N6S3W28p+ExL77TugMKHN5gXklapF67jDfz7lq5ETzQ== } + { integrity: sha512-nBprRf0+jlgxks78G/xq72PipVK+4or9Ypntw0gVZYNTCSK8rg5SeaGV19tV920CMqBD/9UIOiFr23Li/Q8tiA== } engines: { node: '>=14' } peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.25.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) dev: true /@opentelemetry/resources@1.10.1(@opentelemetry/api@1.9.0): @@ -5655,28 +5763,28 @@ packages: '@opentelemetry/semantic-conventions': 1.18.1 dev: false - /@opentelemetry/resources@1.25.0(@opentelemetry/api@1.9.0): + /@opentelemetry/resources@1.25.1(@opentelemetry/api@1.9.0): resolution: - { integrity: sha512-iHjydPMYJ+Li1auveJCq2rp5U2h6Mhq8BidiyE0jfVlDTFyR1ny8AfJHfmFzJ/RAM8vT8L7T21kcmGybxZC7lQ== } + { integrity: sha512-pkZT+iFYIZsVn6+GzM0kSX+u3MSLCY9md+lIJOoKl/P+gJFfxJte/60Usdp8Ce4rOs8GduUpSPNe1ddGyDT1sQ== } engines: { node: '>=14' } peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.25.0 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 - /@opentelemetry/sdk-logs@0.52.0(@opentelemetry/api@1.9.0): + /@opentelemetry/sdk-logs@0.52.1(@opentelemetry/api@1.9.0): resolution: - { integrity: sha512-Dp6g7w7WglrDZMn2yHBMAKRGqQy8C0PUbFovkSwcSsmL47n4FSEc3eeGblZTtueOUW+rTsPJpLHoUpEdS0Wibw== } + { integrity: sha512-MBYh+WcPPsN8YpRHRmK1Hsca9pVlyyKd4BxOC4SsgHACnl/bPp4Cri9hWhVm5+2tiQ9Zf4qSc1Jshw9tOLGWQA== } engines: { node: '>=14' } peerDependencies: '@opentelemetry/api': '>=1.4.0 <1.10.0' dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.52.0 - '@opentelemetry/core': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.25.0(@opentelemetry/api@1.9.0) + '@opentelemetry/api-logs': 0.52.1 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0) dev: true /@opentelemetry/sdk-metrics@1.10.1(@opentelemetry/api@1.9.0): @@ -5705,16 +5813,16 @@ packages: lodash.merge: 4.6.2 dev: false - /@opentelemetry/sdk-metrics@1.25.0(@opentelemetry/api@1.9.0): + /@opentelemetry/sdk-metrics@1.25.1(@opentelemetry/api@1.9.0): resolution: - { integrity: sha512-IF+Sv4VHgBr/BPMKabl+GouJIhEqAOexCHgXVTISdz3q9P9H/uA8ScCF+22gitQ69aFtESbdYOV+Fen5+avQng== } + { integrity: sha512-9Mb7q5ioFL4E4dDrc4wC/A3NTHDat44v4I3p2pLPSxRvqUbDIQyMVr9uK+EU69+HWhlET1VaSrRzwdckWqY15Q== } engines: { node: '>=14' } peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.25.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0) lodash.merge: 4.6.2 dev: true @@ -5755,17 +5863,17 @@ packages: '@opentelemetry/semantic-conventions': 1.10.1 dev: false - /@opentelemetry/sdk-trace-base@1.25.0(@opentelemetry/api@1.9.0): + /@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0): resolution: - { integrity: sha512-6+g2fiRQUG39guCsKVeY8ToeuUf3YUnPkN6DXRA1qDmFLprlLvZm9cS6+chgbW70cZJ406FTtSCDnJwxDC5sGQ== } + { integrity: sha512-C8k4hnEbc5FamuZQ92nTOp8X/diCY56XUTnMiv9UTuJitCzaNNHAVsdm5+HLCdI8SLQsLWIrG38tddMxLVoftw== } engines: { node: '>=14' } peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.25.0 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 /@opentelemetry/sdk-trace-node@1.10.1(@opentelemetry/api@1.9.0): resolution: @@ -5783,19 +5891,19 @@ packages: semver: 7.6.2 dev: false - /@opentelemetry/sdk-trace-node@1.25.0(@opentelemetry/api@1.9.0): + /@opentelemetry/sdk-trace-node@1.25.1(@opentelemetry/api@1.9.0): resolution: - { integrity: sha512-sYdZmNCkqthPpjwCxAJk5aQNLxCOQjT1u3JMGvO6rb3Ic8uFdnzXavP13Md9uYPcZBo+KxetyDhCf0x8wJGRng== } + { integrity: sha512-nMcjFIKxnFqoez4gUmihdBrbpsEnAX/Xj16sGvZm+guceYE0NE00vLhpDVK6f3q8Q4VFI5xG8JjlXKMB/SkTTQ== } engines: { node: '>=14' } peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/core': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/propagator-b3': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/propagator-jaeger': 1.25.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.25.0(@opentelemetry/api@1.9.0) + '@opentelemetry/context-async-hooks': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/propagator-b3': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/propagator-jaeger': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) semver: 7.6.2 dev: true @@ -5811,9 +5919,9 @@ packages: engines: { node: '>=14' } dev: false - /@opentelemetry/semantic-conventions@1.25.0: + /@opentelemetry/semantic-conventions@1.25.1: resolution: - { integrity: sha512-M+kkXKRAIAiAP6qYyesfrC5TOmDpDVtsxuGfPcqd9B/iBrac+E14jYwrgm0yZBUIbIP2OnqC3j+UgkXLm1vxUQ== } + { integrity: sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ== } engines: { node: '>=14' } /@pkgjs/parseargs@0.11.0: @@ -6197,6 +6305,15 @@ packages: tslib: 2.6.3 dev: true + /@smithy/abort-controller@3.1.0: + resolution: + { integrity: sha512-XOm4LkuC0PsK1sf2bBJLIlskn5ghmVxiEBVlo/jg0R8hxASBKYYgOoJEhKWgOr4vWGkN+5rC+oyBAqHYtxjnwQ== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@smithy/chunked-blob-reader-native@3.0.0: resolution: { integrity: sha512-VDkpCYW+peSuM4zJip5WDfqvg2Mo/e8yxOv3VF1m11y7B8KKMKVFtmZWDe36Fvk8rGuWrPZHHXZ7rR7uM5yWyg== } @@ -6212,45 +6329,84 @@ packages: tslib: 2.6.3 dev: true - /@smithy/config-resolver@3.0.1: + /@smithy/config-resolver@3.0.0: resolution: - { integrity: sha512-hbkYJc20SBDz2qqLzttjI/EqXemtmWk0ooRznLsiXp3066KQRTvuKHa7U4jCZCJq6Dozqvy0R1/vNESC9inPJg== } + { integrity: sha512-2GzOfADwYLQugYkKQhIyZyQlM05K+tMKvRnc6eFfZcpJGRfKoMUMYdPlBKmqHwQFXQKBrGV6cxL9oymWgDzvFw== } engines: { node: '>=16.0.0' } dependencies: - '@smithy/node-config-provider': 3.1.0 + '@smithy/node-config-provider': 3.0.0 '@smithy/types': 3.0.0 '@smithy/util-config-provider': 3.0.0 '@smithy/util-middleware': 3.0.0 tslib: 2.6.3 dev: true - /@smithy/core@2.2.0: + /@smithy/config-resolver@3.0.3: + resolution: + { integrity: sha512-4wHqCMkdfVDP4qmr4fVPYOFOH+vKhOv3X4e6KEU9wIC8xXUQ24tnF4CW+sddGDX1zU86GGyQ7A+rg2xmUD6jpQ== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/node-config-provider': 3.1.2 + '@smithy/types': 3.2.0 + '@smithy/util-config-provider': 3.0.0 + '@smithy/util-middleware': 3.0.2 + tslib: 2.6.3 + dev: true + + /@smithy/core@2.0.1: resolution: - { integrity: sha512-ygLZSSKgt9bR8HAxR9mK+U5obvAJBr6zlQuhN5soYWx/amjDoQN4dTkydTypgKe6rIbUjTILyLU+W5XFwXr4kg== } + { integrity: sha512-rcMkjvwxH/bER+oZUPR0yTA0ELD6m3A+d92+CFkdF6HJFCBB1bXo7P5pm21L66XwTN01B6bUhSCQ7cymWRD8zg== } engines: { node: '>=16.0.0' } dependencies: - '@smithy/middleware-endpoint': 3.0.1 - '@smithy/middleware-retry': 3.0.3 + '@smithy/middleware-endpoint': 3.0.0 + '@smithy/middleware-retry': 3.0.1 '@smithy/middleware-serde': 3.0.0 '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.1.1 + '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 '@smithy/util-middleware': 3.0.0 tslib: 2.6.3 dev: true - /@smithy/credential-provider-imds@3.1.0: + /@smithy/core@2.2.3: resolution: - { integrity: sha512-q4A4d38v8pYYmseu/jTS3Z5I3zXlEOe5Obi+EJreVKgSVyWUHOd7/yaVCinC60QG4MRyCs98tcxBH1IMC0bu7Q== } + { integrity: sha512-SpyLOL2vgE6sUYM6nQfu82OirCPkCDKctyG3aMgjMlDPTJpUlmlNH0ttu9ZWwzEjrzzr8uABmPjJTRI7gk1HFQ== } engines: { node: '>=16.0.0' } dependencies: - '@smithy/node-config-provider': 3.1.0 - '@smithy/property-provider': 3.1.0 + '@smithy/middleware-endpoint': 3.0.3 + '@smithy/middleware-retry': 3.0.6 + '@smithy/middleware-serde': 3.0.2 + '@smithy/protocol-http': 4.0.2 + '@smithy/smithy-client': 3.1.4 + '@smithy/types': 3.2.0 + '@smithy/util-middleware': 3.0.2 + tslib: 2.6.3 + dev: true + + /@smithy/credential-provider-imds@3.0.0: + resolution: + { integrity: sha512-lfmBiFQcA3FsDAPxNfY0L7CawcWtbyWsBOHo34nF095728JLkBX4Y9q/VPPE2r7fqMVK+drmDigqE2/SSQeVRA== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/node-config-provider': 3.0.0 + '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 '@smithy/url-parser': 3.0.0 tslib: 2.6.3 dev: true + /@smithy/credential-provider-imds@3.1.2: + resolution: + { integrity: sha512-gqVmUaNoeqyrOAjgZg+rTmFLsphh/vS59LCMdFfVpthVS0jbfBzvBmEPktBd+y9ME4DYMGHFAMSYJDK8q0noOQ== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/node-config-provider': 3.1.2 + '@smithy/property-provider': 3.1.2 + '@smithy/types': 3.2.0 + '@smithy/url-parser': 3.0.2 + tslib: 2.6.3 + dev: true + /@smithy/eventstream-codec@3.0.0: resolution: { integrity: sha512-PUtyEA0Oik50SaEFCZ0WPVtF9tz/teze2fDptW6WRXl+RrEenH8UbEjudOz8iakiMl3lE3lCVqYf2Y+znL8QFQ== } @@ -6311,6 +6467,17 @@ packages: tslib: 2.6.3 dev: true + /@smithy/fetch-http-handler@3.1.0: + resolution: + { integrity: sha512-s7oQjEOUH9TYjctpITtWF4qxOdg7pBrP9eigEQ8SBsxF3dRFV0S28pGMllC83DUr7ECmErhO/BUwnULfoNhKgQ== } + dependencies: + '@smithy/protocol-http': 4.0.2 + '@smithy/querystring-builder': 3.0.2 + '@smithy/types': 3.2.0 + '@smithy/util-base64': 3.0.0 + tslib: 2.6.3 + dev: true + /@smithy/hash-blob-browser@3.0.0: resolution: { integrity: sha512-/Wbpdg+bwJvW7lxR/zpWAc1/x/YkcqguuF2bAzkJrvXriZu1vm8r+PUdE4syiVwQg7PPR2dXpi3CLBb9qRDaVQ== } @@ -6332,6 +6499,17 @@ packages: tslib: 2.6.3 dev: true + /@smithy/hash-node@3.0.2: + resolution: + { integrity: sha512-43uGA6o6QJQdXwAogybdTDHDd3SCdKyoiHIHb8PpdE2rKmVicjG9b1UgVwdgO8QPytmVqHFaUw27M3LZKwu8Yg== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/types': 3.2.0 + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + dev: true + /@smithy/hash-stream-node@3.0.0: resolution: { integrity: sha512-J0i7de+EgXDEGITD4fxzmMX8CyCNETTIRXlxjMiNUvvu76Xn3GJ31wQR85ynlPk2wI1lqoknAFJaD1fiNDlbIA== } @@ -6350,6 +6528,22 @@ packages: tslib: 2.6.3 dev: true + /@smithy/invalid-dependency@3.0.2: + resolution: + { integrity: sha512-+BAY3fMhomtq470tswXyrdVBSUhiLuhBVT+rOmpbz5e04YX+s1dX4NxTLzZGwBjCpeWZNtTxP8zbIvvFk81gUg== } + dependencies: + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + + /@smithy/is-array-buffer@2.2.0: + resolution: + { integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA== } + engines: { node: '>=14.0.0' } + dependencies: + tslib: 2.6.3 + dev: true + /@smithy/is-array-buffer@3.0.0: resolution: { integrity: sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ== } @@ -6377,29 +6571,53 @@ packages: tslib: 2.6.3 dev: true - /@smithy/middleware-endpoint@3.0.1: + /@smithy/middleware-content-length@3.0.2: resolution: - { integrity: sha512-lQ/UOdGD4KM5kLZiAl0q8Qy3dPbynvAXKAdXnYlrA1OpaUwr+neSsVokDZpY6ZVb5Yx8jnus29uv6XWpM9P4SQ== } + { integrity: sha512-/Havz3PkYIEmwpqkyRTR21yJsWnFbD1ec4H1pUL+TkDnE7RCQkAVUQepLL/UeCaZeCBXvfdoKbOjSbV01xIinQ== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/protocol-http': 4.0.2 + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + + /@smithy/middleware-endpoint@3.0.0: + resolution: + { integrity: sha512-aXOAWztw/5qAfp0NcA2OWpv6ZI/E+Dh9mByif7i91D/0iyYNUcKvskmXiowKESFkuZ7PIMd3VOR4fTibZDs2OQ== } engines: { node: '>=16.0.0' } dependencies: '@smithy/middleware-serde': 3.0.0 - '@smithy/node-config-provider': 3.1.0 - '@smithy/shared-ini-file-loader': 3.1.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 '@smithy/types': 3.0.0 '@smithy/url-parser': 3.0.0 '@smithy/util-middleware': 3.0.0 tslib: 2.6.3 dev: true - /@smithy/middleware-retry@3.0.3: + /@smithy/middleware-endpoint@3.0.3: + resolution: + { integrity: sha512-ARAXHodhj4tttKa9y75zvENdSoHq6VGsSi7XS3+yLutrnxttJs6N10UMInCC1yi3/bopT8xug3iOP/y9R6sKJQ== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/middleware-serde': 3.0.2 + '@smithy/node-config-provider': 3.1.2 + '@smithy/shared-ini-file-loader': 3.1.2 + '@smithy/types': 3.2.0 + '@smithy/url-parser': 3.0.2 + '@smithy/util-middleware': 3.0.2 + tslib: 2.6.3 + dev: true + + /@smithy/middleware-retry@3.0.1: resolution: - { integrity: sha512-Wve1qzJb83VEU/6q+/I0cQdAkDnuzELC6IvIBwDzUEiGpKqXgX1v10FUuZGbRS6Ov/P+HHthcAoHOJZQvZNAkA== } + { integrity: sha512-hBhSEuL841FhJBK/19WpaGk5YWSzFk/P2UaVjANGKRv3eYNO8Y1lANWgqnuPWjOyCEWMPr58vELFDWpxvRKANw== } engines: { node: '>=16.0.0' } dependencies: - '@smithy/node-config-provider': 3.1.0 + '@smithy/node-config-provider': 3.0.0 '@smithy/protocol-http': 4.0.0 '@smithy/service-error-classification': 3.0.0 - '@smithy/smithy-client': 3.1.1 + '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 '@smithy/util-middleware': 3.0.0 '@smithy/util-retry': 3.0.0 @@ -6407,6 +6625,22 @@ packages: uuid: 9.0.1 dev: true + /@smithy/middleware-retry@3.0.6: + resolution: + { integrity: sha512-ICsFKp8eAyIMmxN5UT3IU37S6886L879TKtgxPsn/VD/laYNwqTLmJaCAn5//+2fRIrV0dnHp6LFlMwdXlWoUQ== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/node-config-provider': 3.1.2 + '@smithy/protocol-http': 4.0.2 + '@smithy/service-error-classification': 3.0.2 + '@smithy/smithy-client': 3.1.4 + '@smithy/types': 3.2.0 + '@smithy/util-middleware': 3.0.2 + '@smithy/util-retry': 3.0.2 + tslib: 2.6.3 + uuid: 9.0.1 + dev: true + /@smithy/middleware-serde@3.0.0: resolution: { integrity: sha512-I1vKG1foI+oPgG9r7IMY1S+xBnmAn1ISqployvqkwHoSb8VPsngHDTOgYGYBonuOKndaWRUGJZrKYYLB+Ane6w== } @@ -6416,6 +6650,15 @@ packages: tslib: 2.6.3 dev: true + /@smithy/middleware-serde@3.0.2: + resolution: + { integrity: sha512-oT2abV5zLhBucJe1LIIFEcRgIBDbZpziuMPswTMbBQNcaEUycLFvX63zsFmqfwG+/ZQKsNx+BSE8W51CMuK7Yw== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@smithy/middleware-stack@3.0.0: resolution: { integrity: sha512-+H0jmyfAyHRFXm6wunskuNAqtj7yfmwFB6Fp37enytp2q047/Od9xetEaUbluyImOlGnGpaVGaVfjwawSr+i6Q== } @@ -6425,17 +6668,37 @@ packages: tslib: 2.6.3 dev: true - /@smithy/node-config-provider@3.1.0: + /@smithy/middleware-stack@3.0.2: + resolution: + { integrity: sha512-6fRcxomlNKBPIy/YjcnC7YHpMAjRvGUYlYVJAfELqZjkW0vQegNcImjY7T1HgYA6u3pAcCxKVBLYnkTw8z/l0A== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + + /@smithy/node-config-provider@3.0.0: resolution: - { integrity: sha512-ngfB8QItUfTFTfHMvKuc2g1W60V1urIgZHqD1JNFZC2tTWXahqf2XvKXqcBS7yZqR7GqkQQZy11y/lNOUWzq7Q== } + { integrity: sha512-buqfaSdDh0zo62EPLf8rGDvcpKwGpO5ho4bXS2cdFhlOta7tBkWJt+O5uiaAeICfIOfPclNOndshDNSanX2X9g== } engines: { node: '>=16.0.0' } dependencies: - '@smithy/property-provider': 3.1.0 - '@smithy/shared-ini-file-loader': 3.1.0 + '@smithy/property-provider': 3.0.0 + '@smithy/shared-ini-file-loader': 3.0.0 '@smithy/types': 3.0.0 tslib: 2.6.3 dev: true + /@smithy/node-config-provider@3.1.2: + resolution: + { integrity: sha512-388fEAa7+6ORj/BDC70peg3fyFBTTXJyXfXJ0Bwd6FYsRltePr2oGzIcm5AuC1WUSLtZ/dF+hYOnfTMs04rLvA== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/property-provider': 3.1.2 + '@smithy/shared-ini-file-loader': 3.1.2 + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@smithy/node-http-handler@3.0.0: resolution: { integrity: sha512-3trD4r7NOMygwLbUJo4eodyQuypAWr7uvPnebNJ9a70dQhVn+US8j/lCnvoJS6BXfZeF7PkkkI0DemVJw+n+eQ== } @@ -6448,15 +6711,36 @@ packages: tslib: 2.6.3 dev: true - /@smithy/property-provider@3.1.0: + /@smithy/node-http-handler@3.1.0: resolution: - { integrity: sha512-Tj3+oVhqdZgemjCiWjFlADfhvLF4C/uKDuKo7/tlEsRQ9+3emCreR2xndj970QSRSsiCEU8hZW3/8JQu+n5w4Q== } + { integrity: sha512-pOpgB6B+VLXLwAyyvRz+ZAVXABlbAsJ2xvn3WZvrppAPImxwQOPFbeSUzWYMhpC8Tr7yQ3R8fG990QDhskkf1Q== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/abort-controller': 3.1.0 + '@smithy/protocol-http': 4.0.2 + '@smithy/querystring-builder': 3.0.2 + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + + /@smithy/property-provider@3.0.0: + resolution: + { integrity: sha512-LmbPgHBswdXCrkWWuUwBm9w72S2iLWyC/5jet9/Y9cGHtzqxi+GVjfCfahkvNV4KXEwgnH8EMpcrD9RUYe0eLQ== } engines: { node: '>=16.0.0' } dependencies: '@smithy/types': 3.0.0 tslib: 2.6.3 dev: true + /@smithy/property-provider@3.1.2: + resolution: + { integrity: sha512-Hzp32BpeFFexBpO1z+ts8okbq/VLzJBadxanJAo/Wf2CmvXMBp6Q/TLWr7Js6IbMEcr0pDZ02V3u1XZkuQUJaA== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@smithy/protocol-http@4.0.0: resolution: { integrity: sha512-qOQZOEI2XLWRWBO9AgIYuHuqjZ2csyr8/IlgFDHDNuIgLAMRx2Bl8ck5U5D6Vh9DPdoaVpuzwWMa0xcdL4O/AQ== } @@ -6466,6 +6750,15 @@ packages: tslib: 2.6.3 dev: true + /@smithy/protocol-http@4.0.2: + resolution: + { integrity: sha512-X/90xNWIOqSR2tLUyWxVIBdatpm35DrL44rI/xoeBWUuanE0iyCXJpTcnqlOpnEzgcu0xCKE06+g70TTu2j7RQ== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@smithy/querystring-builder@3.0.0: resolution: { integrity: sha512-bW8Fi0NzyfkE0TmQphDXr1AmBDbK01cA4C1Z7ggwMAU5RDz5AAv/KmoRwzQAS0kxXNf/D2ALTEgwK0U2c4LtRg== } @@ -6476,6 +6769,16 @@ packages: tslib: 2.6.3 dev: true + /@smithy/querystring-builder@3.0.2: + resolution: + { integrity: sha512-xhv1+HacDYsOLdNt7zW+8Fe779KYAzmWvzs9bC5NlKM8QGYCwwuFwDBynhlU4D5twgi2pZ14Lm4h6RiAazCtmA== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/types': 3.2.0 + '@smithy/util-uri-escape': 3.0.0 + tslib: 2.6.3 + dev: true + /@smithy/querystring-parser@3.0.0: resolution: { integrity: sha512-UzHwthk0UEccV4dHzPySnBy34AWw3V9lIqUTxmozQ+wPDAO9csCWMfOLe7V9A2agNYy7xE+Pb0S6K/J23JSzfQ== } @@ -6485,6 +6788,15 @@ packages: tslib: 2.6.3 dev: true + /@smithy/querystring-parser@3.0.2: + resolution: + { integrity: sha512-C5hyRKgrZGPNh5QqIWzXnW+LXVrPmVQO0iJKjHeb5v3C61ZkP9QhrKmbfchcTyg/VnaE0tMNf/nmLpQlWuiqpg== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@smithy/service-error-classification@3.0.0: resolution: { integrity: sha512-3BsBtOUt2Gsnc3X23ew+r2M71WwtpHfEDGhHYHSDg6q1t8FrWh15jT25DLajFV1H+PpxAJ6gqe9yYeRUsmSdFA== } @@ -6493,15 +6805,32 @@ packages: '@smithy/types': 3.0.0 dev: true - /@smithy/shared-ini-file-loader@3.1.0: + /@smithy/service-error-classification@3.0.2: + resolution: + { integrity: sha512-cu0WV2XRttItsuXlcM0kq5MKdphbMMmSd2CXF122dJ75NrFE0o7rruXFGfxAp3BKzgF/DMxX+PllIA/cj4FHMw== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/types': 3.2.0 + dev: true + + /@smithy/shared-ini-file-loader@3.0.0: resolution: - { integrity: sha512-dAM7wSX0NR3qTNyGVN/nwwpEDzfV9T/3AN2eABExWmda5VqZKSsjlINqomO5hjQWGv+IIkoXfs3u2vGSNz8+Rg== } + { integrity: sha512-REVw6XauXk8xE4zo5aGL7Rz4ywA8qNMUn8RtWeTRQsgAlmlvbJ7CEPBcaXU2NDC3AYBgYAXrGyWD8XrN8UGDog== } engines: { node: '>=16.0.0' } dependencies: '@smithy/types': 3.0.0 tslib: 2.6.3 dev: true + /@smithy/shared-ini-file-loader@3.1.2: + resolution: + { integrity: sha512-tgnXrXbLMO8vo6VeuqabMw/eTzQHlLmZx0TC0TjtjJghnD0Xl4pEnJtBjTJr6XF5fHMNrt5BcczDXHJT9yNQnA== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@smithy/signature-v4@3.0.0: resolution: { integrity: sha512-kXFOkNX+BQHe2qnLxpMEaCRGap9J6tUGLzc3A9jdn+nD4JdMwCKTJ+zFwQ20GkY+mAXGatyTw3HcoUlR39HwmA== } @@ -6516,12 +6845,26 @@ packages: tslib: 2.6.3 dev: true - /@smithy/smithy-client@3.1.1: + /@smithy/signature-v4@3.1.1: resolution: - { integrity: sha512-tj4Ku7MpzZR8cmVuPcSbrLFVxmptWktmJMwST/uIEq4sarabEdF8CbmQdYB7uJ/X51Qq2EYwnRsoS7hdR4B7rA== } + { integrity: sha512-2/vlG86Sr489XX8TA/F+VDA+P04ESef04pSz0wRtlQBExcSPjqO08rvrkcas2zLnJ51i+7ukOURCkgqixBYjSQ== } engines: { node: '>=16.0.0' } dependencies: - '@smithy/middleware-endpoint': 3.0.1 + '@smithy/is-array-buffer': 3.0.0 + '@smithy/types': 3.2.0 + '@smithy/util-hex-encoding': 3.0.0 + '@smithy/util-middleware': 3.0.2 + '@smithy/util-uri-escape': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + dev: true + + /@smithy/smithy-client@3.0.1: + resolution: + { integrity: sha512-KAiFY4Y4jdHxR+4zerH/VBhaFKM8pbaVmJZ/CWJRwtM/CmwzTfXfvYwf6GoUwiHepdv+lwiOXCuOl6UBDUEINw== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/middleware-endpoint': 3.0.0 '@smithy/middleware-stack': 3.0.0 '@smithy/protocol-http': 4.0.0 '@smithy/types': 3.0.0 @@ -6529,6 +6872,19 @@ packages: tslib: 2.6.3 dev: true + /@smithy/smithy-client@3.1.4: + resolution: + { integrity: sha512-y6xJROGrIoitjpwXLY7P9luDHvuT9jWpAluliuSFdBymFxcl6iyQjo9U/JhYfRHFNTruqsvKOrOESVuPGEcRmQ== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/middleware-endpoint': 3.0.3 + '@smithy/middleware-stack': 3.0.2 + '@smithy/protocol-http': 4.0.2 + '@smithy/types': 3.2.0 + '@smithy/util-stream': 3.0.4 + tslib: 2.6.3 + dev: true + /@smithy/types@3.0.0: resolution: { integrity: sha512-VvWuQk2RKFuOr98gFhjca7fkBS+xLLURT8bUjk5XQoV0ZLm7WPwWPPY3/AwzTLuUBDeoKDCthfe1AsTUWaSEhw== } @@ -6537,6 +6893,14 @@ packages: tslib: 2.6.3 dev: true + /@smithy/types@3.2.0: + resolution: + { integrity: sha512-cKyeKAPazZRVqm7QPvcPD2jEIt2wqDPAL1KJKb0f/5I7uhollvsWZuZKLclmyP6a+Jwmr3OV3t+X0pZUUHS9BA== } + engines: { node: '>=16.0.0' } + dependencies: + tslib: 2.6.3 + dev: true + /@smithy/url-parser@3.0.0: resolution: { integrity: sha512-2XLazFgUu+YOGHtWihB3FSLAfCUajVfNBXGGYjOaVKjLAuAxx3pSBY3hBgLzIgB17haf59gOG3imKqTy8mcrjw== } @@ -6546,6 +6910,15 @@ packages: tslib: 2.6.3 dev: true + /@smithy/url-parser@3.0.2: + resolution: + { integrity: sha512-pRiPHrgibeAr4avtXDoBHmTLtthwA4l8jKYRfZjNgp+bBPyxDMPRg2TMJaYxqbKemvrOkHu9MIBTv2RkdNfD6w== } + dependencies: + '@smithy/querystring-parser': 3.0.2 + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@smithy/util-base64@3.0.0: resolution: { integrity: sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ== } @@ -6571,6 +6944,15 @@ packages: tslib: 2.6.3 dev: true + /@smithy/util-buffer-from@2.2.0: + resolution: + { integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA== } + engines: { node: '>=14.0.0' } + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.6.3 + dev: true + /@smithy/util-buffer-from@3.0.0: resolution: { integrity: sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA== } @@ -6588,42 +6970,78 @@ packages: tslib: 2.6.3 dev: true - /@smithy/util-defaults-mode-browser@3.0.3: + /@smithy/util-defaults-mode-browser@3.0.1: resolution: - { integrity: sha512-3DFON2bvXJAukJe+qFgPV/rorG7ZD3m4gjCXHD1V5z/tgKQp5MCTCLntrd686tX6tj8Uli3lefWXJudNg5WmCA== } + { integrity: sha512-nW5kEzdJn1Bn5TF+gOPHh2rcPli8JU9vSSXLbfg7uPnfR1TMRQqs9zlYRhIb87NeSxIbpdXOI94tvXSy+fvDYg== } engines: { node: '>= 10.0.0' } dependencies: - '@smithy/property-provider': 3.1.0 - '@smithy/smithy-client': 3.1.1 + '@smithy/property-provider': 3.0.0 + '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 bowser: 2.11.0 tslib: 2.6.3 dev: true - /@smithy/util-defaults-mode-node@3.0.3: + /@smithy/util-defaults-mode-browser@3.0.6: + resolution: + { integrity: sha512-tAgoc++Eq+KL7g55+k108pn7nAob3GLWNEMbXhZIQyBcBNaE/o3+r4AEbae0A8bWvLRvArVsjeiuhMykGa04/A== } + engines: { node: '>= 10.0.0' } + dependencies: + '@smithy/property-provider': 3.1.2 + '@smithy/smithy-client': 3.1.4 + '@smithy/types': 3.2.0 + bowser: 2.11.0 + tslib: 2.6.3 + dev: true + + /@smithy/util-defaults-mode-node@3.0.1: resolution: - { integrity: sha512-D0b8GJXecT00baoSQ3Iieu3k3mZ7GY8w1zmg8pdogYrGvWJeLcIclqk2gbkG4K0DaBGWrO6v6r20iwIFfDYrmA== } + { integrity: sha512-TFk+Qb+elLc/MOhtSp+50fstyfZ6avQbgH2d96xUBpeScu+Al9elxv+UFAjaTHe0HQe5n+wem8ZLpXvU8lwV6Q== } engines: { node: '>= 10.0.0' } dependencies: - '@smithy/config-resolver': 3.0.1 - '@smithy/credential-provider-imds': 3.1.0 - '@smithy/node-config-provider': 3.1.0 - '@smithy/property-provider': 3.1.0 - '@smithy/smithy-client': 3.1.1 + '@smithy/config-resolver': 3.0.0 + '@smithy/credential-provider-imds': 3.0.0 + '@smithy/node-config-provider': 3.0.0 + '@smithy/property-provider': 3.0.0 + '@smithy/smithy-client': 3.0.1 '@smithy/types': 3.0.0 tslib: 2.6.3 dev: true - /@smithy/util-endpoints@2.0.1: + /@smithy/util-defaults-mode-node@3.0.6: resolution: - { integrity: sha512-ZRT0VCOnKlVohfoABMc8lWeQo/JEFuPWctfNRXgTHbyOVssMOLYFUNWukxxiHRGVAhV+n3c0kPW+zUqckjVPEA== } + { integrity: sha512-UNerul6/E8aiCyFTBHk+RSIZCo7m96d/N5K3FeO/wFeZP6oy5HAicLzxqa85Wjv7MkXSxSySX29L/LwTV/QMag== } + engines: { node: '>= 10.0.0' } + dependencies: + '@smithy/config-resolver': 3.0.3 + '@smithy/credential-provider-imds': 3.1.2 + '@smithy/node-config-provider': 3.1.2 + '@smithy/property-provider': 3.1.2 + '@smithy/smithy-client': 3.1.4 + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + + /@smithy/util-endpoints@2.0.0: + resolution: + { integrity: sha512-+exaXzEY3DNt2qtA2OtRNSDlVrE4p32j1JSsQkzA5AdP0YtJNjkYbYhJxkFmPYcjI1abuwopOZCwUmv682QkiQ== } engines: { node: '>=16.0.0' } dependencies: - '@smithy/node-config-provider': 3.1.0 + '@smithy/node-config-provider': 3.0.0 '@smithy/types': 3.0.0 tslib: 2.6.3 dev: true + /@smithy/util-endpoints@2.0.3: + resolution: + { integrity: sha512-Dyi+pfLglDHSGsKSYunuUUSFM5V0tz7UDgv1Ex97yg+Xkn0Eb0rH0rcvl1n0MaJ11fac3HKDOH0DkALyQYCQag== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/node-config-provider': 3.1.2 + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@smithy/util-hex-encoding@3.0.0: resolution: { integrity: sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ== } @@ -6641,6 +7059,15 @@ packages: tslib: 2.6.3 dev: true + /@smithy/util-middleware@3.0.2: + resolution: + { integrity: sha512-7WW5SD0XVrpfqljBYzS5rLR+EiDzl7wCVJZ9Lo6ChNFV4VYDk37Z1QI5w/LnYtU/QKnSawYoHRd7VjSyC8QRQQ== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@smithy/util-retry@3.0.0: resolution: { integrity: sha512-nK99bvJiziGv/UOKJlDvFF45F00WgPLKVIGUfAK+mDhzVN2hb/S33uW2Tlhg5PVBoqY7tDVqL0zmu4OxAHgo9g== } @@ -6651,6 +7078,16 @@ packages: tslib: 2.6.3 dev: true + /@smithy/util-retry@3.0.2: + resolution: + { integrity: sha512-HUVOb1k8p/IH6WFUjsLa+L9H1Zi/FAAB2CDOpWuffI1b2Txi6sknau8kNfC46Xrt39P1j2KDzCE1UlLa2eW5+A== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/service-error-classification': 3.0.2 + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@smithy/util-stream@3.0.1: resolution: { integrity: sha512-7F7VNNhAsfMRA8I986YdOY5fE0/T1/ZjFF6OLsqkvQVNP3vZ/szYDfGCyphb7ioA09r32K/0qbSFfNFU68aSzA== } @@ -6666,6 +7103,21 @@ packages: tslib: 2.6.3 dev: true + /@smithy/util-stream@3.0.4: + resolution: + { integrity: sha512-CcMioiaOOsEVdb09pS7ux1ij7QcQ2jE/cE1+iin1DXMeRgAEQN/47m7Xztu7KFQuQsj0A5YwB2UN45q97CqKCg== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/fetch-http-handler': 3.1.0 + '@smithy/node-http-handler': 3.1.0 + '@smithy/types': 3.2.0 + '@smithy/util-base64': 3.0.0 + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-hex-encoding': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + dev: true + /@smithy/util-uri-escape@3.0.0: resolution: { integrity: sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg== } @@ -6674,6 +7126,15 @@ packages: tslib: 2.6.3 dev: true + /@smithy/util-utf8@2.3.0: + resolution: + { integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A== } + engines: { node: '>=14.0.0' } + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.6.3 + dev: true + /@smithy/util-utf8@3.0.0: resolution: { integrity: sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA== } @@ -6693,6 +7154,16 @@ packages: tslib: 2.6.3 dev: true + /@smithy/util-waiter@3.1.0: + resolution: + { integrity: sha512-5OVcC5ZcmmutY208ADY/l2eB4H4DVXs+hPUo/M1spF4/YEmF9DdLkfwBvohej2dIeVJayKY7hMlD0X8j3F3/Uw== } + engines: { node: '>=16.0.0' } + dependencies: + '@smithy/abort-controller': 3.1.0 + '@smithy/types': 3.2.0 + tslib: 2.6.3 + dev: true + /@swc/core-darwin-arm64@1.3.89: resolution: { integrity: sha512-LVCZQ2yGrX2678uMvW66IF1bzcOMqiABi+ioNDnJtAIsE/zRVMEYp1ivbOrH32FmPplBby6CGgJIOT3P4VaP1g== } @@ -6846,7 +7317,7 @@ packages: { integrity: sha512-T0HO+VrU9VbLRiEx/kH4+gwGMHNMIGkp0Pok+p0I33saOOLyhfGvwOKQgvt2qkxzQEV2L5MtGB8EnW4r5d3CqQ== } dependencies: '@textlint/ast-node-types': 12.6.1 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) mdast-util-gfm-autolink-literal: 0.1.3 remark-footnotes: 3.0.0 remark-frontmatter: 3.0.0 @@ -6920,7 +7391,7 @@ packages: resolution: { integrity: sha512-D4PbNRbviKyppS5ivBGyFO29POlySLmA2HyUFE4p5QGazAMM3CwkKWcvTl8gvElSuxRh6FPKL8XmidX873ou4g== } dependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.7 dev: true /@types/cookie@0.6.0: @@ -6992,6 +7463,13 @@ packages: '@types/lodash': 4.14.199 dev: true + /@types/lodash.keyby@4.6.9: + resolution: + { integrity: sha512-N8xfQdZ2ADNPDL72TaLozIL4K1xFCMG1C1T9GN4dOFI+sn1cjl8d4U+POp8PRCAnNxDCMkYAZVD/rOBIWYPT5g== } + dependencies: + '@types/lodash': 4.14.199 + dev: true + /@types/lodash.pick@4.4.9: resolution: { integrity: sha512-hDpr96x9xHClwy1KX4/RXRejqjDFTEGbEMT3t6wYSYeFDzxmMnSKB/xHIbktRlPj8Nii2g8L5dtFDRaNFBEzUQ== } @@ -7027,16 +7505,16 @@ packages: resolution: { integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow== } dependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.7 /@types/node@12.20.55: resolution: { integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== } dev: true - /@types/node@20.14.2: + /@types/node@20.14.7: resolution: - { integrity: sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q== } + { integrity: sha512-uTr2m2IbJJucF3KUxgnGOZvYbN0QgkGyWxG6973HCpMYFy2KfcgYuIwkJQMQkt1VbBMlvWRbpshFTLxnxCZjKQ== } dependencies: undici-types: 5.26.5 @@ -7048,14 +7526,14 @@ packages: resolution: { integrity: sha512-LxJ4iEFcpqc6METwp9f6BV6VVc43m6MfH0VqFosHvrUgfXiFe6ww7R3itkOQ+TCK6Y+Iv/+RnnvtRZnkc5Kc9g== } dependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.7 dev: true /@types/pg@8.11.6: resolution: { integrity: sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ== } dependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.7 pg-protocol: 1.6.1 pg-types: 4.0.2 dev: true @@ -7074,7 +7552,7 @@ packages: resolution: { integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA== } dependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.7 kleur: 3.0.3 dev: false @@ -7161,7 +7639,7 @@ packages: '@typescript-eslint/type-utils': 6.21.0(eslint@9.5.0)(typescript@5.4.5) '@typescript-eslint/utils': 6.21.0(eslint@9.5.0)(typescript@5.4.5) '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) eslint: 9.5.0 graphemer: 1.4.0 ignore: 5.3.1 @@ -7173,9 +7651,9 @@ packages: - supports-color dev: true - /@typescript-eslint/eslint-plugin@7.13.0(@typescript-eslint/parser@7.13.0)(eslint@9.5.0)(typescript@5.4.5): + /@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1)(eslint@9.5.0)(typescript@5.4.5): resolution: - { integrity: sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w== } + { integrity: sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg== } engines: { node: ^18.18.0 || >=20.0.0 } peerDependencies: '@typescript-eslint/parser': ^7.0.0 @@ -7186,11 +7664,11 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.13.0(eslint@9.5.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/type-utils': 7.13.0(eslint@9.5.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.0(eslint@9.5.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.13.0 + '@typescript-eslint/parser': 7.13.1(eslint@9.5.0)(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.13.1 + '@typescript-eslint/type-utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5) + '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.13.1 eslint: 9.5.0 graphemer: 1.4.0 ignore: 5.3.1 @@ -7216,16 +7694,16 @@ packages: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) eslint: 9.5.0 typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@7.13.0(eslint@9.5.0)(typescript@5.4.5): + /@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5): resolution: - { integrity: sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA== } + { integrity: sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A== } engines: { node: ^18.18.0 || >=20.0.0 } peerDependencies: eslint: ^8.56.0 @@ -7234,11 +7712,11 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.13.0 - debug: 4.3.5(supports-color@9.4.0) + '@typescript-eslint/scope-manager': 7.13.1 + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.13.1 + debug: 4.3.4(supports-color@9.4.0) eslint: 9.5.0 typescript: 5.4.5 transitivePeerDependencies: @@ -7254,13 +7732,22 @@ packages: '@typescript-eslint/visitor-keys': 6.21.0 dev: true - /@typescript-eslint/scope-manager@7.13.0: + /@typescript-eslint/scope-manager@7.11.0: resolution: - { integrity: sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng== } + { integrity: sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw== } engines: { node: ^18.18.0 || >=20.0.0 } dependencies: - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/visitor-keys': 7.13.0 + '@typescript-eslint/types': 7.11.0 + '@typescript-eslint/visitor-keys': 7.11.0 + dev: true + + /@typescript-eslint/scope-manager@7.13.1: + resolution: + { integrity: sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg== } + engines: { node: ^18.18.0 || >=20.0.0 } + dependencies: + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/visitor-keys': 7.13.1 dev: true /@typescript-eslint/type-utils@6.21.0(eslint@9.5.0)(typescript@5.4.5): @@ -7276,7 +7763,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) '@typescript-eslint/utils': 6.21.0(eslint@9.5.0)(typescript@5.4.5) - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) eslint: 9.5.0 ts-api-utils: 1.3.0(typescript@5.4.5) typescript: 5.4.5 @@ -7284,9 +7771,9 @@ packages: - supports-color dev: true - /@typescript-eslint/type-utils@7.13.0(eslint@9.5.0)(typescript@5.4.5): + /@typescript-eslint/type-utils@7.13.1(eslint@9.5.0)(typescript@5.4.5): resolution: - { integrity: sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A== } + { integrity: sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg== } engines: { node: ^18.18.0 || >=20.0.0 } peerDependencies: eslint: ^8.56.0 @@ -7295,9 +7782,9 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.0(eslint@9.5.0)(typescript@5.4.5) - debug: 4.3.5(supports-color@9.4.0) + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) + '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5) + debug: 4.3.4(supports-color@9.4.0) eslint: 9.5.0 ts-api-utils: 1.3.0(typescript@5.4.5) typescript: 5.4.5 @@ -7317,9 +7804,15 @@ packages: engines: { node: ^16.0.0 || >=18.0.0 } dev: true - /@typescript-eslint/types@7.13.0: + /@typescript-eslint/types@7.11.0: + resolution: + { integrity: sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w== } + engines: { node: ^18.18.0 || >=20.0.0 } + dev: true + + /@typescript-eslint/types@7.13.1: resolution: - { integrity: sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA== } + { integrity: sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw== } engines: { node: ^18.18.0 || >=20.0.0 } dev: true @@ -7335,7 +7828,7 @@ packages: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.2 @@ -7357,7 +7850,7 @@ packages: dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -7368,9 +7861,9 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree@7.13.0(typescript@5.4.5): + /@typescript-eslint/typescript-estree@7.11.0(typescript@5.4.5): resolution: - { integrity: sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw== } + { integrity: sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ== } engines: { node: ^18.18.0 || >=20.0.0 } peerDependencies: typescript: '*' @@ -7378,9 +7871,32 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/visitor-keys': 7.13.0 - debug: 4.3.5(supports-color@9.4.0) + '@typescript-eslint/types': 7.11.0 + '@typescript-eslint/visitor-keys': 7.11.0 + debug: 4.3.4(supports-color@9.4.0) + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.4 + semver: 7.6.2 + ts-api-utils: 1.3.0(typescript@5.4.5) + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/typescript-estree@7.13.1(typescript@5.4.5): + resolution: + { integrity: sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw== } + engines: { node: ^18.18.0 || >=20.0.0 } + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/visitor-keys': 7.13.1 + debug: 4.3.4(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 @@ -7411,17 +7927,34 @@ packages: - typescript dev: true - /@typescript-eslint/utils@7.13.0(eslint@9.5.0)(typescript@5.4.5): + /@typescript-eslint/utils@7.11.0(eslint@9.5.0)(typescript@5.4.5): + resolution: + { integrity: sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA== } + engines: { node: ^18.18.0 || >=20.0.0 } + peerDependencies: + eslint: ^8.56.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0) + '@typescript-eslint/scope-manager': 7.11.0 + '@typescript-eslint/types': 7.11.0 + '@typescript-eslint/typescript-estree': 7.11.0(typescript@5.4.5) + eslint: 9.5.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/utils@7.13.1(eslint@9.5.0)(typescript@5.4.5): resolution: - { integrity: sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ== } + { integrity: sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ== } engines: { node: ^18.18.0 || >=20.0.0 } peerDependencies: eslint: ^8.56.0 dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0) - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.13.1 + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) eslint: 9.5.0 transitivePeerDependencies: - supports-color @@ -7446,12 +7979,21 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@typescript-eslint/visitor-keys@7.13.0: + /@typescript-eslint/visitor-keys@7.11.0: resolution: - { integrity: sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw== } + { integrity: sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ== } engines: { node: ^18.18.0 || >=20.0.0 } dependencies: - '@typescript-eslint/types': 7.13.0 + '@typescript-eslint/types': 7.11.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@typescript-eslint/visitor-keys@7.13.1: + resolution: + { integrity: sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA== } + engines: { node: ^18.18.0 || >=20.0.0 } + dependencies: + '@typescript-eslint/types': 7.13.1 eslint-visitor-keys: 3.4.3 dev: true @@ -7610,7 +8152,7 @@ packages: { integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== } engines: { node: '>= 6.0.0' } dependencies: - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) transitivePeerDependencies: - supports-color dev: false @@ -8171,7 +8713,6 @@ packages: engines: { node: '>=8' } dependencies: fill-range: 7.0.1 - dev: true /braces@3.0.3: resolution: @@ -9117,7 +9658,7 @@ packages: ms: 2.1.3 dev: true - /debug@4.3.4: + /debug@4.3.4(supports-color@8.1.1): resolution: { integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== } engines: { node: '>=6.0' } @@ -9128,10 +9669,12 @@ packages: optional: true dependencies: ms: 2.1.2 + supports-color: 8.1.1 + dev: true - /debug@4.3.5(supports-color@8.1.1): + /debug@4.3.4(supports-color@9.4.0): resolution: - { integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== } + { integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== } engines: { node: '>=6.0' } peerDependencies: supports-color: '*' @@ -9140,9 +9683,9 @@ packages: optional: true dependencies: ms: 2.1.2 - supports-color: 8.1.1 + supports-color: 9.4.0 - /debug@4.3.5(supports-color@9.4.0): + /debug@4.3.5(supports-color@8.1.1): resolution: { integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== } engines: { node: '>=6.0' } @@ -9153,7 +9696,7 @@ packages: optional: true dependencies: ms: 2.1.2 - supports-color: 9.4.0 + supports-color: 8.1.1 /decamelize-keys@1.1.1: resolution: @@ -10024,14 +10567,14 @@ packages: eslint: '*' eslint-plugin-import: '*' dependencies: - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) enhanced-resolve: 5.15.0 eslint: 9.5.0 eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0) - fast-glob: 3.3.2 - get-tsconfig: 4.7.5 - is-core-module: 2.13.1 + fast-glob: 3.3.1 + get-tsconfig: 4.7.2 + is-core-module: 2.13.0 is-glob: 4.0.3 transitivePeerDependencies: - '@typescript-eslint/parser' @@ -10040,7 +10583,7 @@ packages: - supports-color dev: true - /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.0)(eslint-plugin-import@2.29.1)(eslint@9.5.0): + /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.1)(eslint-plugin-import@2.29.1)(eslint@9.5.0): resolution: { integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg== } engines: { node: ^14.18.0 || >=16.0.0 } @@ -10048,11 +10591,11 @@ packages: eslint: '*' eslint-plugin-import: '*' dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) enhanced-resolve: 5.15.0 eslint: 9.5.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.13.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.13.0)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.13.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.13.1)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0) fast-glob: 3.3.1 get-tsconfig: 4.7.2 is-core-module: 2.13.0 @@ -10095,7 +10638,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@7.13.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@7.13.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0): resolution: { integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== } engines: { node: '>=4' } @@ -10117,11 +10660,11 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 7.13.0(eslint@9.5.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.13.1(eslint@9.5.0)(typescript@5.4.5) debug: 3.2.7 eslint: 9.5.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.13.0)(eslint-plugin-import@2.29.1)(eslint@9.5.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.13.1)(eslint-plugin-import@2.29.1)(eslint@9.5.0) transitivePeerDependencies: - supports-color dev: true @@ -10174,7 +10717,7 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.0)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0): + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0): resolution: { integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== } engines: { node: '>=4' } @@ -10185,7 +10728,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 7.13.0(eslint@9.5.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.13.1(eslint@9.5.0)(typescript@5.4.5) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 @@ -10194,7 +10737,7 @@ packages: doctrine: 2.1.0 eslint: 9.5.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.13.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.13.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -10260,7 +10803,7 @@ packages: vue-eslint-parser: optional: true dependencies: - '@typescript-eslint/utils': 7.13.0(eslint@9.5.0)(typescript@5.4.5) + '@typescript-eslint/utils': 7.11.0(eslint@9.5.0)(typescript@5.4.5) eslint: 9.5.0 minimatch: 9.0.4 natural-compare-lite: 1.4.0 @@ -10362,7 +10905,7 @@ packages: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) escape-string-regexp: 4.0.0 eslint-scope: 8.0.1 eslint-visitor-keys: 4.0.0 @@ -10506,7 +11049,7 @@ packages: human-signals: 5.0.0 is-stream: 3.0.0 merge-stream: 2.0.0 - npm-run-path: 5.3.0 + npm-run-path: 5.1.0 onetime: 6.0.0 signal-exit: 4.1.0 strip-final-newline: 3.0.0 @@ -10567,7 +11110,7 @@ packages: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.7 + micromatch: 4.0.5 /fast-json-stable-stringify@2.1.0: resolution: @@ -10678,7 +11221,6 @@ packages: engines: { node: '>=8' } dependencies: to-regex-range: 5.0.1 - dev: true /fill-range@7.1.1: resolution: @@ -11408,7 +11950,7 @@ packages: engines: { node: '>=8.0.0' } dependencies: content-type: 1.0.5 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) is-retry-allowed: 1.2.0 is-stream: 2.0.1 parse-json: 4.0.0 @@ -11436,7 +11978,7 @@ packages: engines: { node: '>= 6' } dependencies: agent-base: 6.0.2(supports-color@9.4.0) - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) transitivePeerDependencies: - supports-color dev: false @@ -11508,9 +12050,9 @@ packages: parent-module: 1.0.1 resolve-from: 4.0.0 - /import-in-the-middle@1.8.0: + /import-in-the-middle@1.8.1: resolution: - { integrity: sha512-/xQjze8szLNnJ5rvHSzn+dcVXqCAU6Plbk4P24U/jwPmg1wy7IIp9OjKIO5tYue8GSPhDpPDiApQjvBUmWwhsQ== } + { integrity: sha512-yhRwoHtiLGvmSozNOALgjRPFI6uYsds60EoMqqnXyyv+JOIW/BrrLejuTGBt+bq0T5tLzOHrN0T7xYTm4Qt/ng== } dependencies: acorn: 8.11.3 acorn-import-attributes: 1.9.5(acorn@8.11.3) @@ -12334,7 +12876,7 @@ packages: dependencies: chalk: 5.3.0 commander: 12.1.0 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) execa: 8.0.1 lilconfig: 3.1.1 listr2: 8.2.1 @@ -12468,6 +13010,11 @@ packages: { integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== } dev: false + /lodash.keyby@4.6.0: + resolution: + { integrity: sha512-PRe4Cn20oJM2Sn6ljcZMeKgyhTHpzvzFmdsp9rK+6K0eJs6Tws0MqgGFpfX/o2HjcoQcBny1Eik9W7BnVTzjIQ== } + dev: false + /lodash.merge@4.6.2: resolution: { integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== } @@ -12917,7 +13464,7 @@ packages: resolution: { integrity: sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA== } dependencies: - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) parse-entities: 2.0.0 transitivePeerDependencies: - supports-color @@ -12930,7 +13477,6 @@ packages: dependencies: braces: 3.0.2 picomatch: 2.3.1 - dev: true /micromatch@4.0.7: resolution: @@ -13171,7 +13717,7 @@ packages: outvariant: 1.4.2 path-to-regexp: 6.2.1 strict-event-emitter: 0.5.1 - type-fest: 4.9.0 + type-fest: 4.18.1 typescript: 5.4.5 yargs: 17.7.2 dev: true @@ -13440,7 +13986,6 @@ packages: engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } dependencies: path-key: 4.0.0 - dev: false /npm-run-path@5.3.0: resolution: @@ -13448,6 +13993,7 @@ packages: engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } dependencies: path-key: 4.0.0 + dev: false /npm@10.8.1: resolution: @@ -13670,17 +14216,17 @@ packages: { integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== } dev: true - /oclif@4.13.7: + /oclif@4.13.8: resolution: - { integrity: sha512-wK+5w8KTg5oxMA7QjSpeBAIAJuKcpK+74pD5exG6CHNKGFZ2kbFSp6kKiGcplIRM1V6KtM8T78jpfPVgpZQaLA== } + { integrity: sha512-A/e31wMSXgerxwqwb7MvPusPLGap9Hrgbmq6bBlVS+PnBvH/gxzDAMaUNI2Abcpi5KOVB/YyAaODtFHiIf3Szw== } engines: { node: '>=18.0.0' } hasBin: true dependencies: - '@aws-sdk/client-cloudfront': 3.592.0 + '@aws-sdk/client-cloudfront': 3.600.0 '@aws-sdk/client-s3': 3.583.0 - '@inquirer/confirm': 3.1.9 - '@inquirer/input': 2.1.9 - '@inquirer/select': 2.3.5 + '@inquirer/confirm': 3.1.8 + '@inquirer/input': 2.1.10 + '@inquirer/select': 2.3.6 '@oclif/core': 4.0.6 '@oclif/plugin-help': 6.2.3 '@oclif/plugin-not-found': 3.2.5 @@ -13688,7 +14234,7 @@ packages: async-retry: 1.3.3 chalk: 4.1.2 change-case: 4.1.2 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) ejs: 3.1.10 find-yarn-workspace-root: 2.0.0 fs-extra: 8.1.0 @@ -14581,12 +15127,12 @@ packages: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 20.14.2 + '@types/node': 20.14.7 long: 5.2.3 - /protobufjs@7.3.0: + /protobufjs@7.3.2: resolution: - { integrity: sha512-YWD03n3shzV9ImZRX3ccbjqLxj7NokGN0V/ESiBV5xWqrommYHYiihuIyavq03pWSGqlyvYUFmfoMKd+1rPA/g== } + { integrity: sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg== } engines: { node: '>=12.0.0' } requiresBuild: true dependencies: @@ -14600,7 +15146,7 @@ packages: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 20.14.2 + '@types/node': 20.14.7 long: 5.2.3 dev: true @@ -15061,7 +15607,7 @@ packages: { integrity: sha512-+dtWQ7l2lqQDxheaG3jjyN1QI37gEwvzACSgjYi4/C2y+ZTUMeRW8BIOm+9NBKvwaMBUSZfPXVOt1skB0vBkRw== } engines: { node: '>=8.6.0' } dependencies: - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) module-details-from-path: 1.0.3 resolve: 1.22.6 transitivePeerDependencies: @@ -15073,7 +15619,7 @@ packages: { integrity: sha512-3TLx5TGyAY6AOqLBoXmHkNql0HIf2RGbuMgCDT2WO/uGVAPJs6h7Kl+bN6TIZGd9bWhWPwnDnTHGtW8Iu77sdw== } engines: { node: '>=8.6.0' } dependencies: - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) module-details-from-path: 1.0.3 resolve: 1.22.6 transitivePeerDependencies: @@ -15229,10 +15775,10 @@ packages: rollup: 4.18.0 typescript: 5.4.5 optionalDependencies: - '@babel/code-frame': 7.24.7 + '@babel/code-frame': 7.24.6 dev: true - /rollup-plugin-esbuild@6.1.1(esbuild@0.21.5)(rollup@4.18.0): + /rollup-plugin-esbuild@6.1.1(esbuild@0.21.3)(rollup@4.18.0): resolution: { integrity: sha512-CehMY9FAqJD5OUaE/Mi1r5z0kNeYxItmRO2zG4Qnv2qWKF09J2lTy5GUzjJR354ZPrLkCj4fiBN41lo8PzBUhw== } engines: { node: '>=14.18.0' } @@ -15241,9 +15787,9 @@ packages: rollup: ^1.20.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 dependencies: '@rollup/pluginutils': 5.0.5(rollup@4.18.0) - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) es-module-lexer: 1.3.1 - esbuild: 0.21.5 + esbuild: 0.21.3 get-tsconfig: 4.7.2 rollup: 4.18.0 transitivePeerDependencies: @@ -16253,7 +16799,7 @@ packages: '@ts-morph/common': 0.23.0 code-block-writer: 13.0.1 - /ts-node@10.9.2(@types/node@20.14.2)(typescript@5.4.5): + /ts-node@10.9.2(@types/node@20.14.7)(typescript@5.4.5): resolution: { integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== } hasBin: true @@ -16273,7 +16819,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.14.2 + '@types/node': 20.14.7 acorn: 8.10.0 acorn-walk: 8.2.0 arg: 4.1.3 @@ -16329,9 +16875,9 @@ packages: typescript: 5.4.5 dev: false - /tsx@4.15.5: + /tsx@4.15.7: resolution: - { integrity: sha512-iKi8jQ2VBmZ2kU/FkGkL2OSHBHsazsUzsdC/W/RwhKIEsIoZ1alCclZHP5jGfNHEaEWUJFM1GquzCf+4db3b0w== } + { integrity: sha512-u3H0iSFDZM3za+VxkZ1kywdCeHCn+8/qHQS1MNoO2sONDgD95HlWtt8aB23OzeTmFP9IU4/8bZUdg58Uu5J4cg== } engines: { node: '>=18.0.0' } hasBin: true dependencies: @@ -16501,11 +17047,10 @@ packages: { integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g== } engines: { node: '>=14.16' } - /type-fest@4.9.0: + /type-fest@4.18.1: resolution: - { integrity: sha512-KS/6lh/ynPGiHD/LnAobrEFq3Ad4pBzOlJ1wAnJx9N4EYoqFhMfLIBjUT2UEx4wg5ZE+cC1ob6DCSpppVo+rtg== } + { integrity: sha512-qXhgeNsX15bM63h5aapNFcQid9jRF/l3ojDoDFmekDQEUufZ9U4ErVt6SjDxnHp48Ltrw616R8yNc3giJ3KvVQ== } engines: { node: '>=16' } - dev: true /typed-array-buffer@1.0.0: resolution: @@ -16559,9 +17104,9 @@ packages: { integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== } dev: true - /typescript-eslint@7.13.0(eslint@9.5.0)(typescript@5.4.5): + /typescript-eslint@7.13.1(eslint@9.5.0)(typescript@5.4.5): resolution: - { integrity: sha512-upO0AXxyBwJ4BbiC6CRgAJKtGYha2zw4m1g7TIVPSonwYEuf7vCicw3syjS1OxdDMTz96sZIXl3Jx3vWJLLKFw== } + { integrity: sha512-pvLEuRs8iS9s3Cnp/Wt//hpK8nKc8hVa3cLljHqzaJJQYP8oys8GUyIFqtlev+2lT/fqMPcyQko+HJ6iYK3nFA== } engines: { node: ^18.18.0 || >=20.0.0 } peerDependencies: eslint: ^8.56.0 @@ -16570,9 +17115,9 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 7.13.0(@typescript-eslint/parser@7.13.0)(eslint@9.5.0)(typescript@5.4.5) - '@typescript-eslint/parser': 7.13.0(eslint@9.5.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.0(eslint@9.5.0)(typescript@5.4.5) + '@typescript-eslint/eslint-plugin': 7.13.1(@typescript-eslint/parser@7.13.1)(eslint@9.5.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.13.1(eslint@9.5.0)(typescript@5.4.5) + '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5) eslint: 9.5.0 typescript: 5.4.5 transitivePeerDependencies: @@ -16823,17 +17368,17 @@ packages: vfile-message: 2.0.4 dev: true - /vite-node@1.6.0(@types/node@20.14.2): + /vite-node@1.6.0(@types/node@20.14.7): resolution: { integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw== } engines: { node: ^18.0.0 || >=20.0.0 } hasBin: true dependencies: cac: 6.7.14 - debug: 4.3.5(supports-color@9.4.0) + debug: 4.3.4(supports-color@9.4.0) pathe: 1.1.1 picocolors: 1.0.0 - vite: 5.3.1(@types/node@20.14.2) + vite: 5.3.1(@types/node@20.14.7) transitivePeerDependencies: - '@types/node' - less @@ -16845,7 +17390,7 @@ packages: - terser dev: true - /vite@5.3.1(@types/node@20.14.2): + /vite@5.3.1(@types/node@20.14.7): resolution: { integrity: sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ== } engines: { node: ^18.0.0 || >=20.0.0 } @@ -16874,15 +17419,15 @@ packages: terser: optional: true dependencies: - '@types/node': 20.14.2 - esbuild: 0.21.5 + '@types/node': 20.14.7 + esbuild: 0.21.3 postcss: 8.4.38 rollup: 4.18.0 optionalDependencies: fsevents: 2.3.3 dev: true - /vitest@1.6.0(@types/node@20.14.2): + /vitest@1.6.0(@types/node@20.14.7): resolution: { integrity: sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA== } engines: { node: ^18.0.0 || >=20.0.0 } @@ -16908,7 +17453,7 @@ packages: jsdom: optional: true dependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.7 '@vitest/expect': 1.6.0 '@vitest/runner': 1.6.0 '@vitest/snapshot': 1.6.0 @@ -16916,7 +17461,7 @@ packages: '@vitest/utils': 1.6.0 acorn-walk: 8.3.2 chai: 4.3.10 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) execa: 8.0.1 local-pkg: 0.5.0 magic-string: 0.30.5 @@ -16926,8 +17471,8 @@ packages: strip-literal: 2.0.0 tinybench: 2.5.1 tinypool: 0.8.4 - vite: 5.3.1(@types/node@20.14.2) - vite-node: 1.6.0(@types/node@20.14.2) + vite: 5.3.1(@types/node@20.14.7) + vite-node: 1.6.0(@types/node@20.14.7) why-is-node-running: 2.2.2 transitivePeerDependencies: - less diff --git a/test/integration/query.test.ts b/test/integration/query.test.ts index 60af5c885..a1bb91d08 100644 --- a/test/integration/query.test.ts +++ b/test/integration/query.test.ts @@ -610,14 +610,12 @@ describe('integration tests', () => { }); test('Pagination default value', async () => { - await api.tables.createTable({ workspace, region, database, branch: 'main', table: 'planes' }); - await api.tables.setTableSchema({ - workspace, - region, - database, - branch: 'main', - table: 'planes', - schema: { columns: [{ name: 'name', type: 'string' }] } + await api.table.createTable({ + pathParams: { workspace, region, dbBranchName: `${database}:main`, tableName: 'planes' } + }); + await api.table.setTableSchema({ + pathParams: { workspace, region, dbBranchName: `${database}:main`, tableName: 'planes' }, + body: { columns: [{ name: 'name', type: 'string' }] } }); const planes = Array.from({ length: PAGINATION_DEFAULT_SIZE + 50 }, (_, index) => ({ name: `Plane ${index}` })); diff --git a/test/integration/smoke.test.ts b/test/integration/smoke.test.ts index c77ba8a6d..f7f2d59c6 100644 --- a/test/integration/smoke.test.ts +++ b/test/integration/smoke.test.ts @@ -22,7 +22,7 @@ describe('API Client Integration Tests', () => { test('Create, get and delete workspace with new apiKey', async () => { const workspaceName = getWorkspaceName(); - const newApiKey = await api.authentication.createUserAPIKey({ name: `${workspaceName}-key` }); + const newApiKey = await api.authentication.createUserAPIKey({ pathParams: { keyName: `${workspaceName}-key` } }); expect(newApiKey).toBeDefined(); expect(newApiKey.name).toBe(`${workspaceName}-key`); @@ -31,7 +31,7 @@ describe('API Client Integration Tests', () => { const newApi = new XataApiClient({ apiKey: newApiKey.key, host }); const { id: workspace, name } = await newApi.workspaces.createWorkspace({ - data: { name: workspaceName, slug: `${workspaceName}-slug` } + body: { name: workspaceName, slug: `${workspaceName}-slug` } }); await waitForReplication(newApi, workspace); @@ -41,57 +41,47 @@ describe('API Client Integration Tests', () => { console.log('Created workspace', workspace); - const foo = await newApi.workspaces.getWorkspace({ workspace }); + const foo = await newApi.workspaces.getWorkspace({ pathParams: { workspaceId: workspace } }); expect(foo.id).toBe(workspace); expect(foo.slug).toBe(`${workspaceName}-slug`); - const bar = await newApi.workspaces.getWorkspace({ workspace }); + const bar = await newApi.workspaces.getWorkspace({ pathParams: { workspaceId: workspace } }); expect(bar.id).toBe(workspace); expect(bar.slug).toBe(`${workspaceName}-slug`); - const { databaseName: database } = await newApi.database.createDatabase({ - workspace, - database: `data-${workspace}`, - data: { region } + const { databaseName: database } = await newApi.databases.createDatabase({ + pathParams: { workspaceId: workspace, dbName: `data-${workspace}` }, + body: { region } }); await waitForReplication(newApi, workspace, database); console.log('Created database', database); - await newApi.branches.createBranch({ workspace, region, database, branch: 'branch' }); - await newApi.tables.createTable({ workspace, region, database, branch: 'branch', table: 'table' }); - await newApi.tables.setTableSchema({ - workspace, - region, - database, - branch: 'branch', - table: 'table', - schema: { columns: [{ name: 'email', type: 'string' }] } + await newApi.branch.createBranch({ + pathParams: { workspace, region, dbBranchName: `${database}:branch` } + }); + await newApi.table.createTable({ + pathParams: { workspace, region, dbBranchName: `${database}:branch`, tableName: 'table' } + }); + await newApi.table.setTableSchema({ + pathParams: { workspace, region, dbBranchName: `${database}:branch`, tableName: 'table' }, + body: { columns: [{ name: 'email', type: 'string' }] } }); console.log('Created branch, table and schema'); const { id } = await newApi.records.insertRecord({ - workspace, - region, - database, - branch: 'branch', - table: 'table', - record: { email: 'example@foo.bar' } + pathParams: { workspace, region, dbBranchName: `${database}:branch`, tableName: 'table' }, + body: { email: 'example@foo.bar' } }); console.log('Created record', id); const record = await newApi.records.getRecord({ - workspace, - region, - database, - branch: 'branch', - table: 'table', - id + pathParams: { workspace, region, dbBranchName: `${database}:branch`, tableName: 'table', recordId: id } }); expect(record.id).toBeDefined(); @@ -100,24 +90,16 @@ describe('API Client Integration Tests', () => { await waitForSearchIndexing(newApi, workspace, database); const search = await newApi.searchAndFilter.searchTable({ - workspace, - region, - database, - branch: 'branch', - table: 'table', - query: 'example' + pathParams: { workspace, region, dbBranchName: `${database}:branch`, tableName: 'table' }, + body: { query: 'example' } }); expect(search.totalCount).toEqual(1); expect(search.records[0].id).toEqual(id); const failedSearch = await newApi.searchAndFilter.searchTable({ - workspace, - region, - database, - branch: 'branch', - table: 'table', - query: 'random' + pathParams: { workspace, region, dbBranchName: `${database}:branch`, tableName: 'table' }, + body: { query: 'random' } }); expect(failedSearch.totalCount).toEqual(0); @@ -125,37 +107,32 @@ describe('API Client Integration Tests', () => { console.log('Tested search successfully'); - await api.authentication.deleteUserAPIKey({ name: newApiKey.name }); + await api.authentication.deleteUserAPIKey({ pathParams: { keyName: newApiKey.name } }); await waitFailInReplication(newApi, workspace, database); await expect( newApi.records.getRecord({ - workspace, - region, - database, - branch: 'branch', - table: 'table', - id + pathParams: { workspace, region, dbBranchName: `${database}:branch`, tableName: 'table', recordId: id } }) ).rejects.toHaveProperty('message'); console.log('Deleted API key, record is no longer accessible'); - await api.workspaces.deleteWorkspace({ workspace }); - - await expect(api.workspaces.getWorkspace({ workspace })).rejects.toHaveProperty('message'); + await api.workspaces.deleteWorkspace({ pathParams: { workspaceId: workspace } }); - console.log('Deleted workspace, workspace is no longer accessible'); + await expect(api.workspaces.getWorkspace({ pathParams: { workspaceId: workspace } })).rejects.toHaveProperty( + 'message' + ); }); }); async function waitForReplication(api: XataApiClient, workspace: string, database?: string): Promise { try { if (database === undefined) { - await api.database.getDatabaseList({ workspace }); + await api.databases.getDatabaseList({ pathParams: { workspaceId: workspace } }); } else { - await api.branches.getBranchList({ workspace, database, region }); + await api.branch.getBranchList({ pathParams: { workspace, region, dbName: database } }); } } catch (error) { console.log(`Waiting for create ${database === undefined ? 'API key' : 'database'} replication to finish...`); @@ -166,7 +143,7 @@ async function waitForReplication(api: XataApiClient, workspace: string, databas async function waitFailInReplication(api: XataApiClient, workspace: string, database: string): Promise { try { - await api.branches.getBranchList({ workspace, database, region }); + await api.branch.getBranchList({ pathParams: { workspace, region, dbName: database } }); console.log(`Waiting for delete API key replication to finish...`); await new Promise((resolve) => setTimeout(resolve, 2000)); @@ -179,12 +156,8 @@ async function waitFailInReplication(api: XataApiClient, workspace: string, data async function waitForSearchIndexing(api: XataApiClient, workspace: string, database: string): Promise { try { const { aggs } = await api.searchAndFilter.aggregateTable({ - workspace, - database, - region, - branch: 'branch', - table: 'table', - aggs: { total: { count: '*' } } + pathParams: { workspace, region, dbBranchName: `${database}:branch`, tableName: 'table' }, + body: { aggs: { total: { count: '*' } } } }); if (aggs?.total === 1) { diff --git a/test/utils/setup.ts b/test/utils/setup.ts index 4aad29bc7..c35b73dbb 100644 --- a/test/utils/setup.ts +++ b/test/utils/setup.ts @@ -73,10 +73,15 @@ export async function setUpTestEnvironment( const id = Date.now().toString(36); const api = new XataApiClient({ apiKey, fetch, host, clientName: 'sdk-tests' }); - const { databaseName: database } = await api.database.createDatabase({ - workspace, - database: `sdk-integration-test-${prefix}-${id}`, - data: { region }, + + await api.workspaces.updateWorkspaceSettings({ + pathParams: { workspaceId: workspace }, + body: { postgresEnabled: true } + }); + + const { databaseName: database } = await api.databases.createDatabase({ + pathParams: { workspaceId: workspace, dbName: `sdk-integration-test-${prefix}-${id}` }, + body: { region }, headers: { 'X-Xata-Files': 'true' } }); @@ -93,14 +98,14 @@ export async function setUpTestEnvironment( }; const { edits } = await api.migrations.compareBranchWithUserSchema({ - workspace, - region, - database, - branch: 'main', - schema + pathParams: { workspace, region, dbBranchName: `${database}:main` }, + body: { schema } }); - await api.migrations.applyBranchSchemaEdit({ workspace, region, database, branch: 'main', edits }); + await api.migrations.applyBranchSchemaEdit({ + pathParams: { workspace, region, dbBranchName: `${database}:main` }, + body: { edits } + }); let span: Span | undefined; @@ -110,7 +115,7 @@ export async function setUpTestEnvironment( }, afterAll: async () => { try { - await api.database.deleteDatabase({ workspace, database }); + await api.databases.deleteDatabase({ pathParams: { workspaceId: workspace, dbName: database } }); } catch (e) { // Ignore error, delete database during ES snapshot fails console.error('Delete database failed', e);