diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..e4cbd6b --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,80 @@ +{ + "env": { + "node": true, + "es2022": true, + "mocha": true + }, + "parserOptions": { + "sourceType": "module" + }, + "extends": "eslint:recommended", + "rules": { + "no-console": 0, + "no-class-assign": 1, + "no-cond-assign": 1, + "no-const-assign": 1, + "no-constant-condition": [1, {"checkLoops": false}], + "no-constant-binary-expression": 1, + "no-control-regex": 1, + "no-debugger": 1, + "no-delete-var": 1, + "no-dupe-args": 1, + "no-dupe-class-members": 1, + "no-dupe-keys": 1, + "no-duplicate-case": 1, + "no-empty": 1, + "no-empty-character-class": 1, + "no-empty-pattern": 1, + "no-eval": 1, + "no-ex-assign": 1, + "no-extra-boolean-cast": 1, + "no-extra-semi": 1, + "no-fallthrough": 1, + "no-func-assign": 1, + "no-implicit-globals": 1, + "no-implied-eval": 1, + "no-inner-declarations": 1, + "no-invalid-regexp": 1, + "no-invalid-this": 1, + "no-irregular-whitespace": 1, + "no-mixed-spaces-and-tabs": 1, + "no-native-reassign": 1, + "no-negated-in-lhs": 1, + "no-obj-calls": 1, + "no-octal": 1, + "no-redeclare": 1, + "no-regex-spaces": 1, + "no-sparse-arrays": 1, + "no-trailing-spaces": 1, + "no-this-before-super": 1, + "no-throw-literal": 1, + "no-undef": 1, + "no-undef-init": 1, + "no-unexpected-multiline": 1, + "no-unreachable": 1, + "no-unused-vars": [1, {"argsIgnorePattern":"^ignored"}], + "no-useless-call": 1, + "no-useless-computed-key": 1, + "no-useless-concat": 1, + "no-useless-constructor": 1, + "no-useless-escape": 1, + "no-useless-rename": 1, + "block-scoped-var": 1, + "callback-return": 1, + "complexity": 1, + "constructor-super": 1, + "default-case": 1, + "handle-callback-err": 1, + "require-yield": 1, + "semi": 1, + "use-isnan": 1, + "valid-typeof": 1, + "arrow-spacing": [1, {"before":true, "after":true}], + "func-call-spacing": [1, "never"], + "semi-spacing": [1, {"before": false, "after": true}], + "space-before-function-paren": [1, {"anonymous": "never", "named": "never", "asyncArrow": "always"}], + "brace-style": [1, "1tbs", {"allowSingleLine": true}], + "quotes": [1, "single", { "avoidEscape": true }] + } +} + diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..f16c8eb --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,38 @@ +name: test + +on: + workflow_dispatch: + push: + branches: [ "*" ] + +jobs: + test: + runs-on: ubuntu-latest + + services: + dynamodb-local: + image: amazon/dynamodb-local:latest + ports: + - 8000:8000 + + steps: + - uses: actions/checkout@v3 + with: + persist-credentials: false + - uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: install deps + run: npm ci + + - name: lint + run: npm run-script lint + + - name: test + run: npm run-script test + env: + AWS_REGION: eu-west-1 + AWS_ACCESS_KEY_ID: dummy + AWS_SECRET_ACCESS_KEY: dummy + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a48a290 --- /dev/null +++ b/.gitignore @@ -0,0 +1,118 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# dynamodb-local database +api/test/dynamodb-local/docker/dynamodb/shared-local-instance.db + +# static site build +site/build +site/deploy +site/old + +# .tap files +.tap/ + +# inkscape backups +*.svg.*.svg diff --git a/index.js b/index.js new file mode 100644 index 0000000..a19cd1d --- /dev/null +++ b/index.js @@ -0,0 +1,1507 @@ +'use strict'; +// dead simple Object Document Mapper for dynamodb, supporting single-table design. +const { DynamoDBClient, CreateTableCommand, DescribeTableCommand, UpdateTableCommand, DeleteTableCommand } = require('@aws-sdk/client-dynamodb'); +const { DynamoDBDocumentClient, PutCommand, GetCommand, BatchGetCommand, DeleteCommand, QueryCommand } = require('@aws-sdk/lib-dynamodb'); +const Ajv = require('ajv'); +const ObjectID = require('bson-objectid'); + +const {inspect} = require('util'); + +// internal types for AJV +const kExtendedTypeDate = Symbol('extendedType:date'); +const kExtendedTypeBuffer = Symbol('extendedType:buffer'); + +// this AJV instance is used for general validation, compiled schemas do not modify data +const ajv = new Ajv({ + useDefaults: true +}); + +// this AJV instance is used for marshalling our built-in types before saving to Dynamo (e.g. Date -> number) +const marshallingAjv = new Ajv({ + useDefaults: true +}); + +// this AJV instance is used for unmarshalling out built-in types after loading from Dynamo (e.g. number -> Date) +// in this case defaults are also used +const unMarshallingAjv = new Ajv({ + useDefaults: true +}); + +// this AJV instance is used for checking query values against parts of the model schema, so it needs to ignore defaults +const defaultIgnoringAjv = new Ajv({ + useDefaults: false +}); + +// add our internal types: +const extendedTypeKeyword = { + keyword: 'extendedType', + validate: function extendedTypeValidate(schema, data){ + if (schema === kExtendedTypeDate) { + if (data instanceof Date) { + return true; + } else { + extendedTypeValidate.errors = [{keyword:'extendedType', message:'must be a Date', params:{dataWas:data}}]; + return false; + } + } else if (schema === kExtendedTypeBuffer) { + if (Buffer.isBuffer(data)) { + return true; + } else { + extendedTypeValidate.errors = [{keyword:'extendedType', message:'must be a Buffer', params:{dataWas:data}}]; + return false; + } + } else { + extendedTypeValidate.errors = [{keyword:'extendedType', message:'is an unknown extended type', params:{schemaWas:schema}}]; + return false; + } + } +}; +ajv.addKeyword(extendedTypeKeyword); +defaultIgnoringAjv.addKeyword(extendedTypeKeyword); + +// Marshalling of built-in types to dynamodb types: +marshallingAjv.addKeyword({ + keyword: 'extendedType', + modifying: true, + validate: function validateMarshall(schema, data, parentSchema, ctx) { + if (schema === kExtendedTypeDate) { + /* c8 ignore next 3 */ + if (!ctx.parentData) { + throw new Error('Cannot marshall types that are the root data: there is no parent to assign on.'); + } + if (data instanceof Date) { + ctx.parentData[ctx.parentDataProperty] = data.getTime(); + return true; + } else { + validateMarshall.errors = [{keyword:'extendedType', message:'must be a Date', params:{dataWas:data}}]; + return false; + } + } else if (schema === kExtendedTypeBuffer) { + if (Buffer.isBuffer(data)) { + // buffers do not need marshalling (only unmarshalling from Uint8Array) + return true; + } else { + validateMarshall.errors = [{keyword:'extendedType', message:'must be a Buffer', params:{dataWas:data}}]; + return false; + } + } else { + validateMarshall.errors = [{keyword:'extendedType', message:'is an unknown extended type', params:{schemaWas:schema}}]; + return false; + } + } +}); + +// UnMarshalling of dynamodb types to built-in types: +unMarshallingAjv.addKeyword({ + keyword: 'extendedType', + modifying: true, + validate: function validateUnMarshall(schema, data, parentSchema, ctx) { + /* c8 ignore next 3 */ + if (!ctx.parentData) { + throw new Error('Cannot unmarshall types that are the root data: there is no parent to assign on.'); + } + if (schema === kExtendedTypeDate) { + if (typeof data === 'number') { + ctx.parentData[ctx.parentDataProperty] = new Date(data); + return true; + } else { + validateUnMarshall.errors = [{keyword:'extendedType', message:`Expected marshalled type of Date property ${ctx.parentDataProperty} to be a number (got ${typeof data})`, params:{dataWas:data}}]; + return false; + } + } else if (schema === kExtendedTypeBuffer) { + if (data?.constructor === Uint8Array) { + ctx.parentData[ctx.parentDataProperty] = Buffer.from(data.buffer, data.byteOffset, data.byteLength); + return true; + } else { + validateUnMarshall.errors = [{keyword:'extendedType', message:`Expected marshalled type of Buffer property ${ctx.parentDataProperty} to be a Uint8Array (got ${typeof data})`, params:{dataWas:data}}]; + return false; + } + } else { + validateUnMarshall.errors = [{keyword:'extendedType', message:'is an unknown extended type', params:{schemaWas:schema}}]; + return false; + } + } +}); + +// Marshalling of query values: +const marshallValue = (propSchema, value) => { + // anything which is a date in the schema needs marshalling to a number: + if (propSchema?.extendedType === kExtendedTypeDate) { + return value.getTime(); + } else { + return value; + } +}; + +const indexSpecSchema = ajv.compile({ + type: 'object', + properties: { + 'hashKey': {type:'string'}, + 'sortKey': {type:'string'} + }, + required: ['hashKey'], + additionalProperties: false +}); + +const validTableName = /^[a-zA-Z0-9_.-]{3,255}$/; +const validIndexName = /^[a-zA-Z0-9_.-]{3,255}$/; + +const supportedQueryConditions = new Map([['$gt','>'], ['$gte','>='], ['$lt','<'], ['$lte','<=']]); + +const kModelTable = Symbol(); +const kModelSchema = Symbol(); +const kModelLogger = Symbol(); +const kTableIsReady = Symbol(); +const kTableDDBClient = Symbol(); +const kTableIndices = Symbol(); +const kTableGetBackoffDelayMs = Symbol(); +const kSchemaCompiled = Symbol('schema:compiled'); +const kSchemaMarshall = Symbol('schema:marshall'); +const kSchemaUnMarshall = Symbol('schema:unmarshall'); +const kSchemaIndices = Symbol('schema:indices'); +const kSchemaNewId = Symbol('schema:newId'); +const kOptionSkipValidation = Symbol(); + +// Built-in schema types +const DocId = { type:'string', minLength:1, maxLength:1024 }; +const Timestamp = { extendedType: kExtendedTypeDate }; +const Binary = { extendedType: kExtendedTypeBuffer }; +const TypeFieldType = { type:'string', minLength:1, maxLength:1024 }; + +// Built-in schema types that are compared by identity in order to identify special field names +const DocIdField = Object.assign({}, DocId); +const TypeField = Object.assign({}, TypeFieldType); +const CreatedAtField = Object.assign({}, Timestamp); +const UpdatedAtField = Object.assign({}, Timestamp); + +const delayMs = async (ms) => new Promise(resolve => setTimeout(resolve, ms)); + +const deepCloneObjectsAndArrays = (v) => { + if (Array.isArray(v)) { + return v.map(deepCloneObjectsAndArrays); + } else if ((v?.constructor === Object) || (v instanceof BaseModel)) { + return Object.fromEntries(Object.entries(v).map(([k,v]) => [k, deepCloneObjectsAndArrays(v)])); + } else { + return v; + } +}; + +// helper function so we can do Promise.all(iterableOfPromises) with early cancellation by another promise (which may resolve or reject) +async function promiseAllWithCancellation(iterable, cancellation) { + if (cancellation) { + if (typeof cancellation.then !== 'function') { + throw new TypeError('Cancellation must be thenable.'); + } + let cancelled = false, resolved = false; + let cancellationValue, resolvedValue, rejectedValue; + await Promise.race((function*() { + yield Promise.all(iterable).then( + (v) => {resolvedValue = v; resolved = true;}, + (e) => rejectedValue = e + ); + yield cancellation.then( + (v) => {cancelled = true; cancellationValue = v;}, + (e) => {cancelled = true; cancellationValue = e;} + ); + })()); + if (cancelled) { + if (cancellationValue instanceof Error) { + throw cancellationValue; + } else { + throw new Error('Operation cancelled.'); + } + } else if (resolved) { + return resolvedValue; + } else { + throw rejectedValue; + } + } else { + return Promise.all(iterable); + } +} + +const indexDescriptionsEqual = (a, b) => { + // TODO: not comparing NonKeyAttributes here, but should be + return a && b && + a.IndexName === b.IndexName && + a.KeySchema.length === b.KeySchema.length && + a.Projection.ProjectionType === b.Projection.ProjectionType && + a.KeySchema.every((el, i) => { + return el.AttributeName === b.KeySchema[i].AttributeName && + el.KeyType === b.KeySchema[i].KeyType; + }); +}; + +class Table { + // public fields + name = ''; + client = null; + docClient = null; + + // private fields: + #models = new Map(); + #idFieldName = ''; + #typeFieldName = ''; + #clientShouldBeDestroyed = false; + #logger = null; + + // protected fields that other classes need direct access to + [kTableIsReady] = false; + [kTableDDBClient] = null; + [kTableIndices] = []; + + constructor(options) { + // TODO: The marshall options should be fixed? + let { name, client, clientOptions } = options; + + if (!validTableName.exec(name)) { + throw new Error(`Invalid table name "${name}": Must be between 3 and 255 characters long, and may contain only the characters a-z, A-Z, 0-9, '_', '-', and '.'.`); + } + this.#logger = options.logger.child({table: name}); + if (!client) { + client = new DynamoDBClient(clientOptions); + } + this.name = name; + this.client = client; + this.docClient = DynamoDBDocumentClient.from(client); + this[kTableDDBClient] = this.docClient; + this.#clientShouldBeDestroyed = !options.client; + } + + // public methods: + // wait for this table to be ready + async ready({allowAliasedSchemas, waitForIndexes}={}) { + if (this[kTableIsReady] && !waitForIndexes) { + return; + } else if (!this.client) { + throw new Error('Connection has been destroyed.'); + } + if (!this.#models.size) { + throw new Error('At least one schema is required in a table.'); + } + // check for and create indexes: + const {idField, typeField} = this.#basicReadyChecks({allowAliasedSchemas}); + this.#idFieldName = idField; + this.#typeFieldName = typeField; + + const requiredIndexes = this.#requiredIndexes(); + this[kTableIndices] = requiredIndexes; + const {uniqueRequiredAttributes} = this.#checkIndexCompatibility(requiredIndexes); + + try { + await this[kTableDDBClient].send(new CreateTableCommand({ + TableName: this.name, + // the id field (table key), as well as any attributes referred to + // by indexes need to be defined at table creation + AttributeDefinitions: uniqueRequiredAttributes, + KeySchema: [ + { AttributeName: this.#idFieldName, KeyType: 'HASH' } + ], + BillingMode: 'PAY_PER_REQUEST', + GlobalSecondaryIndexes: requiredIndexes.map(x => x.index), + })); + } catch (err) { + // ResourceInUseException is only thrown if the table already exists + if (err.name !== 'ResourceInUseException') { + /* c8 ignore next 2 */ + throw err; + } + } + + let tableHasRequiredIndexes; + let missingIndexes = []; + let differentIndexes = []; + let response; + let created = false; + do { + tableHasRequiredIndexes = true; + response = await this[kTableDDBClient].send(new DescribeTableCommand({TableName: this.name})); + if (response.Table.TableStatus === 'CREATING') { + /* c8 ignore next */ + await new Promise(resolve => setTimeout(resolve, 500)); + } else if (response.Table.TableStatus === 'ACTIVE' || response.Table.TableStatus === 'UPDATING') { + this.#logger.info('Table %s now %s', this.name, response.Table.TableStatus); + created = true; + } else { + /* c8 ignore next 2 */ + throw new Error(`Table ${this.name} status is ${response.Table.TableStatus}.`); + } + // check if we have all the required indexes + for (const {index, requiredAttributes} of requiredIndexes) { + const match = response.Table.GlobalSecondaryIndexes?.find(i => i.IndexName === index.IndexName); + if (!match) { + missingIndexes.push({index, requiredAttributes}); + tableHasRequiredIndexes = false; + } else if (!indexDescriptionsEqual(match, index)){ + differentIndexes.push({index, requiredAttributes}); + tableHasRequiredIndexes = false; + } + // TODO: while we don't need to check for missing + // requiredAttributes, we should check for incompatible + // requiredAttributes returned from DescribeTableCommand I think, + // as those could prevent index creation? + } + } while (!created); + + if (!tableHasRequiredIndexes) { + await this.#updateIndexes({differentIndexes, missingIndexes, existingIndexes:response.Table.GlobalSecondaryIndexes}); + } + + if (waitForIndexes) { + await this.#waitForIndexes(); + } + + this[kTableIsReady] = true; + } + + // assume that the table is ready (e.g. if connecting to the DB from a + // short-lived lambda function, and you know the table has been created + // correctly already). + assumeReady() { + // still do a quick check that the registered models are compatible: + this.#basicReadyChecks(); + // the list of indexes needs initialising for the query api + this[kTableIndices] = this.#requiredIndexes(); + // TODO: not sure if index compatibility should be checked, this could be relatively expensive: + this.#checkIndexCompatibility(this[kTableIndices]); + this[kTableIsReady] = true; + } + + async destroyConnection() { + this[kTableIsReady] = false; + if (this.#clientShouldBeDestroyed) { + this.client.destroy(); + this.#clientShouldBeDestroyed = false; + } + this.client = this.docClient = null; + this.#models.clear(); + } + + model(schema){ + if (!(schema instanceof Schema)) { + throw new Error('The model schema must be a valid DynamoDM.Schema().'); + } + // add the schema to the table's schema list and return a corresponding + // model that can be used to create and retrieve documents,or return the + // existing model if this schema has already been added. + // Validating most compatibility is done in Table.ready() + if (this.#models.has(schema)) { + return this.#models.get(schema); + } + if (this[kTableIsReady]) { + throw new Error(`Table ${this.name} ready() has been called, so more schemas cannot be added now.`); + } + + const model = createModel({table:this, schema, logger:this.#logger}); + this.#models.set(schema, model); + + return model; + } + + async getById(id) { + // load a model by id only (without knowing its type in advance). The + // type is inferred from the id, and requires the id to be of the form + // {schemaName}.{anything}, via the Schema->Models map this.#models: + const matchingModels = [...this.#models.entries()].filter(([s,ignored_m]) => id.startsWith(`${s.name}.`)).map(([ignored_s,m]) => m); + if (matchingModels.length > 1) { + throw new Error(`Table has multiple ambiguous model types for id "${id}", so it cannot be loaded generically.`); + } else if (matchingModels.length === 0) { + throw new Error(`Table has no matching model type for id "${id}", so it cannot be loaded.`); + } + return matchingModels[0].getById(id); + } + + async deleteTable() { + this.#logger.info({}, 'Deleting tqble %s', this.name); + await this[kTableDDBClient].send(new DeleteTableCommand({ TableName: this.name })); + } + + // protected methods + [kTableGetBackoffDelayMs] = (retryNumber) => { + // TODO, should be configurable by table options + const exponent = 2; + const delayRandomness = 0.75; // 0 = no jitter, 1 = full jitter + const maxRetries = 5; + if (retryNumber >= maxRetries) { + throw new Error('Request failed: maximum retries exceeded.'); + } + return (exponent ** retryNumber) * ((1-delayRandomness) + delayRandomness * Math.random()); + }; + + // private methods: + #basicReadyChecks({allowAliasedSchemas} = {}) { + const idProps = new Set(); + const typeProps = new Set(); + const typeNames = new Map(); + for (const schema of this.#models.keys()) { + idProps.add(schema.idFieldName); + typeProps.add(schema.typeFieldName); + if (!typeNames.has(schema.name)) typeNames.set(schema.name, []); + typeNames.get(schema.name).push(schema); + } + if (!allowAliasedSchemas) { + for (const [name, schemas] of typeNames) { + if (schemas.length > 1) { + throw new Error(`Schemas in the same table must have unique names (${name} referrs to multiple unique schemas).`); + } + } + } + if (idProps.size > 1) { + throw new Error(`Schemas in the same table must have the same idFieldName (encountered:${[...idProps].join(',')}).`); + } + if (typeProps.size > 1) { + throw new Error(`Schemas in the same table must have the same typeFieldName (encountered:${[...typeProps].join(',')}).`); + } + return { + idField: idProps.values().next().value, + typeField: typeProps.values().next().value + }; + } + + #requiredIndexes() { + const requiredIndexes = [ + { + index: { + // The built-in type index, + IndexName: 'type', + KeySchema: [ + { AttributeName: this.#typeFieldName, KeyType: 'HASH' }, + { AttributeName: this.#idFieldName, KeyType: 'RANGE'} + ], + Projection: { ProjectionType: 'KEYS_ONLY' }, + }, + requiredAttributes: [ + { AttributeName: this.#idFieldName, AttributeType: 'S' }, + { AttributeName: this.#typeFieldName, AttributeType: 'S' } + ], + hashKey: this.#typeFieldName, + sortKey: this.#idFieldName + } + ]; + for (const schema of this.#models.keys()) { + requiredIndexes.push(...schema[kSchemaIndices]); + } + return requiredIndexes; + } + + #checkIndexCompatibility(allRequiredIndexes) { + const uniqueRequiredAttributes = []; + const attributeTypes = new Map(); + const indexNames = new Map(); + for (const {index, requiredAttributes} of allRequiredIndexes) { + for (const {AttributeName, AttributeType} of requiredAttributes) { + // store all the types we encounter for each attribute name for comparison: + if(!attributeTypes.has(AttributeName)) { + attributeTypes.set(AttributeName, AttributeType); + uniqueRequiredAttributes.push({AttributeName, AttributeType}); + } else if (attributeTypes.get(AttributeName) !== AttributeType) { + let offendingSchemas = []; + let offendingIndexes = []; + let offendingDefinitions = []; + for (const schema of this.#models.keys()) { + for (const schemaIndex of schema[kSchemaIndices]) { + for (const attr of schemaIndex.requiredAttributes) { + if (attr.AttributeName === AttributeName) { + offendingSchemas.push(schema.name); + offendingIndexes.push(schemaIndex.index.IndexName); + offendingDefinitions.push(attr.AttributeType); + break; + } + } + } + } + throw new Error(`Schema(s) "${offendingSchemas.join(', ')}" define incompatible types (${offendingDefinitions.join(',')}) for ".${AttributeName}" in index(es) "${offendingIndexes.join(', ')}".`); + } + } + if(!indexNames.has(index.IndexName)) { + indexNames.set(index.IndexName, index); + } else if(!indexDescriptionsEqual(index, indexNames.get(index.IndexName))) { + let offendingSchemas = []; + let offendingDefinitions = []; + for (const schema of this.#models.keys()) { + for (const schemaIndex of schema[kSchemaIndices]) { + if (schemaIndex.index.IndexName === index.IndexName) { + offendingSchemas.push(schema.name); + offendingDefinitions.push(schemaIndex.index); + break; + } + } + } + throw new Error(`Schema(s) "${offendingSchemas.join(', ')}" define incompatible versions of index "${index.IndexName}".`); + } + } + return {uniqueRequiredAttributes}; + } + + async #updateIndexes({differentIndexes, missingIndexes, existingIndexes}) { + if (differentIndexes.length) { + this.#logger.warn({existingIndexes, differentIndexes}, `WARNING: indexes "${differentIndexes.map(i => i.index.IndexName).join(',')}" differ from the current specifications, but these will not be automatically updated.`); + } + // FIXME: we can only add one missing index at a time, so just try to + // add the first one. Need a createIndexes option, as this could be a + // long wait if we need to create many? (Subscriber limit exceeded: + // Only 1 online index can be created or deleted simultaneously per + // table -> each update table command can only create one index.... + // "You can create or delete only one global secondary index per + // UpdateTable operation.") + if (missingIndexes.length) { + const updates = { + TableName: this.name, + GlobalSecondaryIndexUpdates: [], + AttributeDefinitions: [] + }; + // we only need to include the attribute definitions required by + // the indexes being created, existing attribute definitions used + // by other indexes do not need to be repeated: + // FIXME see above, only adding the first missing one: + //for (const missingIndex of missingIndexes) { + // updates.GlobalSecondaryIndexUpdates.push({Create: missingIndex.index}); + // updates.AttributeDefinitions = updates.AttributeDefinitions.concat(missingIndex.requiredAttributes); + //} + const missingIndex = missingIndexes.shift(); + updates.GlobalSecondaryIndexUpdates.push({Create: missingIndex.index}); + updates.AttributeDefinitions = updates.AttributeDefinitions.concat(missingIndex.requiredAttributes); + + this.#logger.info({updates}, 'Updating table %s.', this.name); + await this[kTableDDBClient].send(new UpdateTableCommand(updates)); + } + } + + async #waitForIndexes() { + let response; + while (true) { + response = await this[kTableDDBClient].send(new DescribeTableCommand({TableName: this.name})); + // TODO: should be able to cover this actually + /* c8 ignore else */ + if (response.Table.TableStatus === 'ACTIVE') { + break; + } else if (response.Table.TableStatus === 'UPDATING'){ + await new Promise(resolve => setTimeout(resolve, 500)); + } else { + throw new Error(`Table ${this.name} status is ${response.Table.TableStatus}.`); + } + } + } +} + +class BaseModel { + // public fields: + // (none - the intention is that any name can be used for a model property name) + + // private fields: + #modelIsNew = false; + #logger = null; + + constructor({schema, params, options, logger}) { + params = params ?? {}; + if (!params[schema.idFieldName]){ + params[schema.idFieldName] = schema[kSchemaNewId](params, options); + } + if (!params[schema.typeFieldName]){ + params[schema.typeFieldName] = schema.name; + } + // when creating via unmarshalling, the unmarshall process will have + // already validated the data against the schema, so this step can be + // skipped: + if (!options?.[kOptionSkipValidation]) { + const validate = schema[kSchemaCompiled]; + const valid = validate(params); + if (!valid) { + const e = new Error(`Document does not match schema for ${schema.name}: ${validate.errors[0]?.instancePath ?? ''} ${validate.errors[0]?.message}.`); + e.validationErrors = validate.errors; + throw e; + } + } + this.#modelIsNew = true; + this.#logger = logger; + + Object.assign(this, params); + return this; + } + + // public methods: + async save() { return this.#save(); } + async remove() { return this.#remove(); } + async toObject({virtuals=true, ...otherOptions}={}) { return this.#toObject({virtuals, ...otherOptions}); } + + // public static methods: + // options: {ConsistentRead: true, abortSignal: ...} ... dynamoDB consistent read option (defaults to false), and dynamoDB abortSignal options + static async getById(id, options) { + // get one model by its id + // forward the derived class we were called on to the private + // implementation (since the private implementation must be called on + // the base class) + return BaseModel.#getById(this, id, options); + } + + // TODO: I don't think this should be public, but it's nice to be able to test it directly + // options: {ConsistentRead: true, abortSignal: ...} ... dynamoDB consistent read option (defaults to false), and dynamoDB abortSignal options + static async getByIds(ids, options) { + // get an array of models (of the same type) by id + return BaseModel.#getByIds(this, ids, options); + } + + // Query API + // * using options.abortSignal (from an AbortController) for cancellation, and passing this through to the underlying AWS command send() calls. + // * queryMany supports options.limit + // * queryMany is the preferred option, queryIterator might be added... + // * TODO startAfter option: the dynamodb 'LastEvaluatedKey' is the primary key value of the index which is being scanned, and might include the table PK and SK as well? It should be possible to construct LastEvaluatedKey though. + // * alternatively, could have a 'skip' but there is no efficient way to implement 'skip', so this is probably a bad idea. + // + // * cancelling is hard for a user to use... they would need to wrap everything in try...finally, and ensure no other fallible operations are attempted within the finally block, it's much nicer for most users to return a complete array of the requested results, up to a specified limit, after a possible continuation token from a previous call, and return a continuation token for the further pagination too, hence favouring the queryMany over a queryIterator API + // + // implemented = x + // + // x async .queryOne(query, options) -> doc + // x async .queryMany(query, options) -> [doc, ...] + // async .queryIterator(query, ?options) -> async iterator (doc) + // x async .queryOneId(query, options) -> id + // x async .queryManyIds(query, options) -> [id, ...] + // async .queryIteratorIds(query, ?options) -> async iterator (id) + // async Raw queries only support ids: + // async .rawQueryOneId(options) -> id + // async .rawQueryManyIds(options) -> [id, ...] + // async .rawQueryIteratorIds(options, cancelationPromise) -> async iterator (id) + + // Query API Methods: + // For all non-ids methods a separate request is required to fetch the models, rather than just their IDs, which uses options from options.rawFetchOptions + // + // returns a model, or null + static async queryOne(query, options) { + // TODO: would be better to specialise this, but for now just use queryMany with limit:1, and rawQueryOptions.Limit: 1, note that rawQueryOptions.Limit:1 would be a bad choice if rawQueryOptions.FilterExpression is provided, so if you provide a FilterExpression also set Limit to something higher + options = Object.assign({}, options, {limit:1, rawQueryOptions: Object.assign({Limit:1}, options?.rawQueryOptions)}); + return (await this.queryMany(query, options))[0] || null; + } + // returns a model id, or null + static async queryOneId(query, options) { + options = Object.assign({}, options, {limit:1, rawQueryOptions: Object.assign({Limit:1}, options?.rawQueryOptions)}); + return (await this.queryManyIds(query, options))[0] || null; + } + + // return an array of up to options.limit items, starting from options.startAfter + // supported options: + // { + // limit: N, limit on the total number of returned items. Distinct from + // the dynamoDB Limit option, which limits the number of evaluated + // items, the query will be paginated until either the entire + // result set has been evaluated or N matching items have been + // found. Defaults to 50; + // + // abortSignal: an AbortSignal (or compatible) that can be used by the + // caller to interrupt in-progress operations. + // (https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal#implementing_an_abortable_api), + // this will be passed as options.abortSignal to all + // underlying AWS SDK APIs which are used. + // + // startAfter: from which an ExclusiveStartKey is + // constructed. ExclusiveStartKey for the dynamodb document + // client is of the form {hasKeyName:hashKeyVal, + // sortKeyName:sortKeyVal} for the hashkey and optionally + // sortKey of the index being queried. + // + // rawQueryOptions: { + // ... raw options passed to DynamoDB.QueryCommand for the query phase, e.g. ScanIndexForward: false to reverse the results + // } + // rawFetchOptions: { + // ... raw options passed to DynamoDB.GetItemsCommand for the fetch phase, e.g. ConsistentRead: true for strongly consistent reads + // } + // } + static async queryMany(query, options) { + let {rawQueryOptions, rawFetchOptions, ...otherOptions} = options ?? {}; + // TODO: schema for otherOptions which assigns default limit, checks types of cancelled, cancel, limit + otherOptions = Object.assign({limit: 50}, otherOptions); + + // returns an array of models (possibly empty) + const rawQuery = BaseModel.#convertQuery(this, query, Object.assign({startAfter: otherOptions.startAfter, limit: otherOptions.limmit}, rawQueryOptions)); + const pending = []; + // ... relying on #rawQueryIdsBatchIterator to return the right number in total, based on otherOptions.limit + for await (const ids of BaseModel.#rawQueryIdsBatchIterator(this, rawQuery, otherOptions)) { + // start fetching the models from the IDs of this batch immediately, but don't await yet so requests can be parallelised + pending.push(BaseModel.#getByIds(this, ids, Object.assign({abortSignal: otherOptions.abortSignal}, rawFetchOptions))); + } + return (await Promise.all(pending)).flat(); + } + static async queryManyIds(query, options) { + // options are as queryMany, except Ids are returned, so there are no rawFetchOptions + let {rawQueryOptions, ...otherOptions} = options ?? {}; + otherOptions = Object.assign({limit: 50}, otherOptions); + const rawQuery = BaseModel.#convertQuery(this, query, Object.assign({startAfter: otherOptions.startAfter, limit: otherOptions.limmit}, rawQueryOptions)); + const results = []; + for await (const batch of BaseModel.#rawQueryIdsBatchIterator(this, rawQuery, otherOptions)) { + results.push(batch); + } + return results.flat(); + } + + // TODO: I'm not sure queryIterator is a useful API, at least for the non-Ids case? The hidden internal batching isn't very useful? + // TODO: if this api is supported, it will need to listen to the abortSignal inbetween yielding each result, in addition to passing the abortSignal the AWS sdk + // yield all the results of this query up to options.limit (which may be undefined,==Infinity), handling continuation internally, until .return or .throw is called on the returned generator + // static async* queryIterator(query, options) { + // } + // static async* queryIteratorIds(query, options) { + // } + + // TODO: deprecate other query APIs, but keep rawQueryIds? Rename rawQueryIteratorIds? + static async* rawQueryIds({KeyConditionExpression, ExpressionAttributeNames, ExpressionAttributeValues, IndexName, sendOptions, ...otherOptions}) { + yield* BaseModel.#rawQueryIds(this, { + KeyConditionExpression, ExpressionAttributeNames, ExpressionAttributeValues, IndexName, sendOptions, ...otherOptions + }); + } + static async* rawQuery(options) { yield* BaseModel.#rawQuery(this, options); } + static async rawQueryOneId(options) { return BaseModel.#rawQueryOneId(this, options); } + static async rawQueryOne(options) { return BaseModel.#rawQueryOne(this, options); } + static async* listAllIds(options) { yield* BaseModel.#listAllIds(this, options); } + static async* query(query, options) { + this[kModelLogger].warn({query}, 'Deprecation: query* is deprecated in favour of queryMany'); + yield* BaseModel.#query(this, query, options); + } + + + // private methods: + async #save() { + const DerivedModel = this.constructor; + const schema = DerivedModel[kModelSchema]; + const table = DerivedModel[kModelTable]; + // TODO, should add a version field, and use a ConditionExpression on its equality to the current version https://stackoverflow.com/questions/46531331/how-to-prevent-a-dynamodb-item-being-overwritten-if-an-entry-already-exists + if (!table[kTableIsReady]) { + await table.ready(); + } + // update timestamp fields + const now = new Date(); + if (this.#modelIsNew && schema.createdAtFieldName) { + this[schema.createdAtFieldName] = now; + } + if (schema.updatedAtFieldName) { + this[schema.updatedAtFieldName] = now; + } + // check against schema, and marshal types for db: + const properties = deepCloneObjectsAndArrays(this); + const marshall = schema[kSchemaMarshall]; + const marshallValid = marshall(properties); + if (!marshallValid) { + const e = new Error(`Document does not match schema for ${schema.name}: ${marshall.errors[0]?.instancePath ?? ''} ${marshall.errors[0]?.message}.`); + e.validationErrors = schema[kSchemaCompiled].errors; + throw e; + } + // NOTE: this makes it possible to remove properties by setting .prop = + // undefined; ajv allows .prop = undefined through the schema, but to + // actually get the dynamodb client to delete the field we need to + // delete .prop instead (passing undefined will cause an error like + // "Cannot read properties of undefined (reading 'S')"): + for (const [k, v] of Object.entries(properties)) { + if (typeof v === 'undefined') { + delete properties[k]; + } + } + // if the model is new, check that we are not saving a duplicate: + const commandArgs = { + TableName: table.name, + Item: properties + }; + if (this.#modelIsNew) { + commandArgs.ConditionExpression = 'attribute_not_exists(#idFieldName)'; + commandArgs.ExpressionAttributeNames = { '#idFieldName': schema.idFieldName }; + } + const command = new PutCommand(commandArgs); + this.#logger.trace({command}, 'save %s', this.id); + try { + const response = await table[kTableDDBClient].send(command); + this.#logger.trace({response}, 'save %s response', this.id); + } catch (e) { + if(e.name === 'ConditionalCheckFailedException') { + throw new Error(`An item already exists with id field .${schema.idFieldName}="${this[schema.idFieldName]}"`); + } else { + /* c8 ignore next 2 */ + throw e; + } + } + // after saving once, we're no longer new + this.#modelIsNew = false; + return this; + } + + async #remove(){ + const table = this.constructor[kModelTable], + schema = this.constructor[kModelSchema]; + // TODO, should add a version field, and use a ConditionExpression on its equaltiy to the current version https://stackoverflow.com/questions/46531331/how-to-prevent-a-dynamodb-item-being-overwritten-if-an-entry-already-exists + if (!table[kTableIsReady]) { + /* c8 ignore next 2 */ + await table.ready(); + } + const command = new DeleteCommand({ + TableName: table.name, + Key: { [schema.idFieldName]: this[schema.idFieldName] } + }); + this.#logger.trace({command}, 'remove %s', this.id); + const data = await table[kTableDDBClient].send(command); + this.#logger.trace({response: data}, 'remove %s response', this.id); + return this; + } + + async #toObject(options) { + const schema = this.constructor[kModelSchema]; + let r = Object.assign(Object.create(null), this); + if (options?.virtuals !== false) { + // include virtuals by enumerating the definition keys (even + // enumerable virtuals are not included without doing this, as they + // are defined on the prototype, and Object.assign only assigns + // *own* enumerable properties) + for (const k of Object.keys(schema.virtuals)) { + r[k] = this[k]; + } + } + // run the series of schema.converters over the value. These can be + // used (for example) to remove fields from a public api, add + // asynchronously computed fields, or populate ids to object values: + for (const convertor of schema.converters) { + r = await convertor.call(this, r, options); + } + return r; + } + + // private static methods: + static #createFromMarshalled(DerivedModel, params) { + const schema = DerivedModel[kModelSchema]; + const unmarshall = schema[kSchemaUnMarshall]; + const valid = unmarshall(params); + if (!valid) { + // if we've loaded a model of a different type, and there is nothing + let e; + if (params.type !== DerivedModel[kModelSchema].name) { + e = new Error(`Document does not match schema for ${schema.name}. The loaded document has a different type "${params.type}", and the schema is incompatible: ${unmarshall.errors[0]?.instancePath ?? ''} ${unmarshall.errors[0]?.message}.`); + } else { + e = new Error(`Document does not match schema for ${schema.name}: ${unmarshall.errors[0]?.instancePath ?? ''} ${unmarshall.errors[0]?.message}.`); + } + e.validationErrors = unmarshall.errors; + throw e; + } + const instance = new DerivedModel(params, {[kOptionSkipValidation]: true}); + // tag this instance as returned from the db, so when it is saved we do not check against overwrites + instance.#modelIsNew = false; + return instance; + } + + // get an instance of this schema by id + static async #getById(DerivedModel, id, rawOptions) { + // only the ConsistentRead option is supported + const { ConsistentRead, abortSignal } = rawOptions ?? {}; + const table = DerivedModel[kModelTable]; + const schema = DerivedModel[kModelSchema]; + if (!table[kTableIsReady]) { + /* c8 ignore next 2 */ + await table.ready(); + } + if ((typeof id !== 'string') || (!id.length)) { + throw new Error('Invalid id: must be string of nonzero length.'); + } + const sendOptions = { + ...(abortSignal && {abortSignal}) + }; + const command = new GetCommand(Object.assign({ + TableName: table.name, + Key: { + [schema.idFieldName]: id + } + }, ConsistentRead? {ConsistentRead} : undefined)); + DerivedModel[kModelLogger].trace({command, sendOptions}, 'getById %s', id); + const data = await table[kTableDDBClient].send(command, sendOptions); + DerivedModel[kModelLogger].trace({response: data}, 'getById response %s', id); + if (!data.Item) { + return null; + } else { + return this.#createFromMarshalled(DerivedModel, data.Item); + } + } + + // get an array of instances of this schema by id + // At most 100 items can be fetched at one time (the limit to the dynamodb BatchGetItem request size) + static async #getByIds(DerivedModel, ids, rawOptions) { + // only the ConsistentRead option is supported + const { ConsistentRead, abortSignal } = rawOptions ?? {}; + const table = DerivedModel[kModelTable]; + const schema = DerivedModel[kModelSchema]; + if (!table[kTableIsReady]) { + /* c8 ignore next 2 */ + await table.ready(); + } + if (!Array.isArray(ids)) { + throw new Error('Invalid ids: must be array of strings of nonzero length.'); + } + for(const id of ids) { + if ((typeof id !== 'string') || (!id.length)) { + throw new Error('Invalid ids: must be array of strings of nonzero length.'); + } + } + const sendOptions = { + ...(abortSignal && {abortSignal}) + }; + let Keys = ids.map(id => ({ [schema.idFieldName]: id })); + const results = new Map(); + let retryCount = 0; + while(Keys.length) { + const command = new BatchGetCommand({ + RequestItems: { + [table.name]: Object.assign({ + Keys, + }, ConsistentRead? {ConsistentRead} : undefined) + }, + }); + DerivedModel[kModelLogger].trace({command, sendOptions}, 'getByIds %s', ids); + const response = await table[kTableDDBClient].send(command, sendOptions); + DerivedModel[kModelLogger].trace({response}, 'getByIds response %s', ids); + response.Responses[table.name].forEach(data => { + results.set(data[schema.idFieldName], data); + }); + Keys = response?.UnprocessedKeys?.[table.name]?.Keys ?? []; + // exponential backoff as rescommended + // https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.Errors.html#Programming.Errors.RetryAndBackoff + // since unprocessed keys might be caused by read capacity throttling: + retryCount += 1; + await delayMs(table[kTableGetBackoffDelayMs](retryCount)); + } + // return the results by mapping the original ids, so that the results are in the same order + return ids.map( + id => { + const data = results.get(id); + return data? this.#createFromMarshalled(DerivedModel, data) : null; + } + ); + } + + // query for an instance of this schema, an async generator returning the + // ids of the stored records that match the query. Use getById to get the + // object for each ID. + static async* #rawQueryIds(DerivedModel, {KeyConditionExpression, ExpressionAttributeNames, ExpressionAttributeValues, IndexName, sendOptions, ...otherOptions}) { + const table = DerivedModel[kModelTable]; + const schema = DerivedModel[kModelSchema]; + if (!table[kTableIsReady]) { + /* c8 ignore next 2 */ + await table.ready(); + } + const commandParams = { + ...otherOptions, + TableName: table.name, + IndexName, + KeyConditionExpression, + ExpressionAttributeNames, + ExpressionAttributeValues + }; + let response; + let returned = 0; + const limit = otherOptions.totalLimit ?? Infinity; + do { + const command = new QueryCommand(commandParams); + DerivedModel[kModelLogger].trace({command}, 'rawQueryIds'); + response = await table[kTableDDBClient].send(command, sendOptions); + DerivedModel[kModelLogger].trace({response: response}, 'rawQueryIds response'); + + for (const item of response.Items) { + returned += 1; + yield item[schema.idFieldName]; + if (returned >= limit) { + break; + } + } + commandParams.ExclusiveStartKey = response.LastEvaluatedKey; + } while (response.LastEvaluatedKey && returned < limit); + } + + // query for instances of this schema, an async generator returning arrays of ids matching the query, up to options.limit. + static async* #rawQueryIdsBatchIterator(DerivedModel, rawQuery, options) { + const {limit, abortSignal} = options?? {}; + const table = DerivedModel[kModelTable]; + const schema = DerivedModel[kModelSchema]; + if (!table[kTableIsReady]) { + /* c8 ignore next 2 */ + await table.ready(); + } + const sendOptions = { + ...(abortSignal && {abortSignal}) + }; + let response; + let limitRemaining = limit ?? Infinity; + do { + const command = new QueryCommand(rawQuery); + DerivedModel[kModelLogger].trace({command}, 'rawQueryIdsBatch'); + response = await table[kTableDDBClient].send(command, sendOptions); + DerivedModel[kModelLogger].trace({response: response}, 'rawQueryIdsBatch response'); + + if (response.Items.length > limitRemaining) { + yield response.Items.slice(0, limitRemaining).map(item => item[schema.idFieldName]); + break; + } else { + limitRemaining -= response.Items.length; + yield response.Items.map(item => item[schema.idFieldName]); + } + rawQuery.ExclusiveStartKey = response.LastEvaluatedKey; + } while (response.LastEvaluatedKey); + } + + static async* #rawQuery(DerivedModel, options) { + for await(const id of this.#rawQueryIds(DerivedModel, options)) { + yield this.#getById(DerivedModel, id); + } + } + + static async #rawQueryOneId(DerivedModel, options) { + const table = DerivedModel[kModelTable]; + const schema = DerivedModel[kModelSchema]; + if (!table[kTableIsReady]) { + /* c8 ignore next 2 */ + await table.ready(); + } + const commandParams = { + ...options, + TableName: table.name, + Limit: 1 + }; + const response = await table[kTableDDBClient].send(new QueryCommand(commandParams)); + return response?.Items?.[0]?.[schema.idFieldName]; + } + + static async #rawQueryOne(DerivedModel, options) { + const id = await this.#rawQueryOneId(DerivedModel, options); + if (id) { + return await this.#getById(DerivedModel, id); + } else { + return null; + } + } + + // TODO: this should just be query()/find() with no args? + static async* #listAllIds(DerivedModel, options) { + const schema = DerivedModel[kModelSchema]; + for await (const val of this.#rawQueryIds(DerivedModel, { + ...options, + IndexName: 'type', + KeyConditionExpression: '#typeFieldName = :type', + ExpressionAttributeValues: { + ':type': schema.name + }, + ExpressionAttributeNames: { '#typeFieldName': schema.typeFieldName } + })){ + yield val; + } + } + + static #queryEntries(queryObject) { + // return {key: keyFieldName, value: queryValue, condition: '=','<','>'} based on a mongodb-like query object: + // { key1: value1} -> {key: key1, value: value1, condition: '='} + // { key1: {$gt: value1}} -> {key: key1, value: value1, condition: '>'} + // { key1: {$lt: value1}} -> {key: key1, value: value1, condition: '<'} + return Object.entries(queryObject).map( ([k,v]) => { + if (typeof v === 'object') { + const conditions = Object.keys(v).filter(k => k.startsWith('$')); + if (conditions.length > 1) { + throw new Error(`Only a single ${[...supportedQueryConditions.keys()].join('/')} condition is supported in the simple query api.`); + } else if (conditions.length === 1) { + const conditionOp = supportedQueryConditions.get(conditions[0]); + if (conditionOp) { + return {key:k, value: v[conditions[0]], condition:conditionOp}; + } else { + throw new Error(`Condition "${conditions[0]}" is not supported.`); + } + } else { + return {key:k, value:v, condition:'='}; + } + } else { + return {key:k, value:v, condition:'='}; + } + }); + } + + // convert the simple mongoose-style object query (+options) into a raw query for DynamoDB for the specified model type: + static #convertQuery(DerivedModel, query, options) { + // TODO: the original intent of supporting merging in additional + // ExpressionAttributeNames and ExpressionAttributeValues here was that + // a caller could use this simple query API but provide their own raw + // FilterExpression in options (with corresponding + // ExpressionAttributeNames and ExpressionAttributeValues), but in + // practise this is not useful without additional projected attributes + // on indexes, so I'm not sure this should be supported. + const {ExpressionAttributeNames, ExpressionAttributeValues, startAfter, ...otherOptions} = options ?? {}; + const table = DerivedModel[kModelTable]; + const schema = DerivedModel[kModelSchema]; + const queryEntries = this.#queryEntries(query); + + if (queryEntries.length !== 1 && queryEntries.length !== 2) { + // TODO: possibly in the future indexes with additional projected attributes could be supported, and additional query entries could be converted into a FilterExpression + throw new Error(`Unsupported query: "${inspect(query, {breakLength:Infinity})}" Queries must have at most two properties to match against index hash and range attributes.`); + } + // check all the indexes for ones that include all of the query entries: + let matchingIndexes = table[kTableIndices].filter(index => { + if (queryEntries.length === 1) { + return index.hashKey === queryEntries[0].key; + } else { + if ((index.hashKey === queryEntries[0].key && queryEntries[0].condition === '=') && index.sortKey === queryEntries[1].key) { + return true; + } else if ((index.hashKey === queryEntries[1].key && queryEntries[1].condition === '=') && index.sortKey === queryEntries[0].key) { + return true; + } else { + return false; + } + } + }); + if (!matchingIndexes.length) { + throw new Error(`Unsupported query: "${inspect(query, {breakLength:Infinity})}". No index found for query fields [${queryEntries.map(x => x.key).join(', ')}]`); + } else if (matchingIndexes.length > 1) { + DerivedModel[kModelLogger].warn({matchingIndexes, query}, 'multiple indexes match query'); + if (queryEntries.length === 1) { + // if we only have a hash key to query by, prefer indexes that only have a hash key + const bestIndexes = matchingIndexes.filter(index => !index.sortKey); + if (bestIndexes.length) { + matchingIndexes = bestIndexes; + } + } + } + const index = matchingIndexes[0]; + + for (const entry of queryEntries){ + // check query values against schema, and marshall: + const keySchema = schema.source.properties[entry.key]; + if (keySchema) { + const valid = defaultIgnoringAjv.validate(keySchema, entry.value); + if (!valid) { + const e = new Error(`Value does not match schema for ${entry.key}: ${defaultIgnoringAjv.errors[0]?.instancePath ?? ''} ${defaultIgnoringAjv.errors[0]?.message}.`); + e.validationErrors = defaultIgnoringAjv.errors; + throw e; + } + } + entry.value = marshallValue(keySchema, entry.value); + } + let ExclusiveStartKey; + if (startAfter) { + if (!(startAfter instanceof DerivedModel)) { + throw new Error(`options.startAfter must be a ${DerivedModel.name} model instance. To specify ExclusiveStartKey directly use options.rawQueryOptions.ExclusiveStartKey instead.`); + } + // The ExclusiveStartKey is composed of the GSI hash key, the GSI range key (if it exists), the table hash key + ExclusiveStartKey = { + // this will be the table's hash key. Table range key is currently not supported: + [schema.idFieldName]: options.startAfter[schema.idFieldName], + [index.hashKey]: options.startAfter[index.hashKey], + ...(index.sortKey && {[index.sortKey]: options.startAfter[index.sortKey]}), + }; + } + const KeyConditionExpression = queryEntries.map((v,i) => `#fieldName${i} ${v.condition} :fieldValue${i}`).join(' AND '); + const mergedExprAttributeValues = Object.fromEntries(queryEntries.map(({value},i) => [`:fieldValue${i}`, value]).concat(Object.entries(ExpressionAttributeValues ?? {}))); + const mergedExprAttributeNames = Object.fromEntries(queryEntries.map(({key},i) => [`#fieldName${i}`, key]).concat(Object.entries(ExpressionAttributeNames ?? {}))); + + return Object.assign(Object.create(null), { + IndexName: index.index.IndexName, + TableName: table.name, + KeyConditionExpression, + ExpressionAttributeValues: mergedExprAttributeValues, + ExpressionAttributeNames: mergedExprAttributeNames, + ...(ExclusiveStartKey && {ExclusiveStartKey}), + // TODO: not sure if this will mess up pagination? + // set the dynamodb Limit to the options limit, or the maximum supported, so that we don't evaluate more items than necessary + // ...(options.limit && {Limit:options.limit}) + }, otherOptions); + } + + static async* #query(DerivedModel, query, options) { + DerivedModel[kModelLogger].warn({query}, 'Deprecation: #query* is deprecated in favour of #rawQueryIdsBatchIterator*'); + const rawQuery = this.#convertQuery(DerivedModel, query, options); + DerivedModel[kModelLogger].info({query, raw:rawQuery}, 'simple query'); + yield* this.#rawQuery(DerivedModel, rawQuery); + } +} + +const createModel = function({table, schema, logger}) { + // create a unique class for this type, all the functionality is implemented in the base class + const childLogger = logger.child({model: schema.name}); + class Model extends BaseModel { + // public static fields + static table = table; + static name = schema.name; + + // protected (accessed by base class) static fields: + static [kModelTable] = table; + static [kModelSchema] = schema; + static [kModelLogger] = childLogger; + + constructor(params, options){ + super({schema, params, options, logger: childLogger}); + } + } + // override the name: + Object.defineProperty(Model.prototype.constructor, 'name', {value: `Model_${schema.name}`}); + + // TODO: more comprehensive reserved name list + if (schema.methods.constructor) { + throw new Error('The name \'constructor\' is reserved and cannot be used for a method.'); + } + + Object.assign(Model, schema.statics); + Object.assign(Model.prototype, schema.methods); + // generate getters and setters for virtuals: + Object.defineProperties(Model.prototype, generateGettersAndSetters(schema)); + + // check that converters are all valid: + for (const [i, f] of schema.converters.entries()) { + if (typeof f !== 'function') { + throw new Error(`Converters must be functions or async functions: typeof converters[${i}] is ${typeof f}.`); + } + } + + return Model; +}; + +const attributeTypeFromSchema = (indexName, schema, propertyName) => { + if (typeof (schema?.properties?.[propertyName]) === 'undefined') { + throw new Error(`The schema must define the type of property .${propertyName} used by index "${indexName}".`); + } else if (schema?.properties?.[propertyName].type === 'string') { + return 'S'; + } else if (schema?.properties?.[propertyName]?.extendedType === kExtendedTypeBuffer) { + return 'B'; + } else if (schema?.properties?.[propertyName]?.extendedType === kExtendedTypeDate || schema?.properties?.[propertyName].type === 'number') { + return 'N'; + } + throw new Error(`The schema type of property .${propertyName}, "${JSON.stringify(schema?.properties?.[propertyName])}" used by index "${indexName}" is not indexable.`); +}; + +const parseIndexSpecification = (index, schemaSource) => { + if (!index) return []; + const indices = []; + for (const [indexName, indexSpec] of Object.entries(index)) { + if (!validIndexName.exec(indexName)) { + throw new Error(`Invalid index name "${indexName}": Must be between 3 and 255 characters long, and may contain only the characters a-z, A-Z, 0-9, '_', '-', and '.'.`); + } + if (indexName === 'type') { + throw new Error('Invalid index name "type": this name is reserved for the built-in type index.'); + } + const index = { + IndexName: indexName, + Projection: { ProjectionType: 'KEYS_ONLY' } + }; + const requiredAttributes = []; + let hashKey, sortKey; + + if (indexSpec === 1 || indexSpec === true) { + index.KeySchema = [ + { AttributeName: indexName, KeyType: 'HASH' } + ]; + requiredAttributes.push({ + AttributeName: indexName, + AttributeType: attributeTypeFromSchema(indexName, schemaSource, indexName) + }); + hashKey = indexName; + } else if (indexSpecSchema(indexSpec)){ + index.KeySchema = [ + { AttributeName: indexSpec.hashKey, KeyType: 'HASH'} + ]; + requiredAttributes.push({ + AttributeName: indexSpec.hashKey, + AttributeType: attributeTypeFromSchema(indexName, schemaSource, indexSpec.hashKey) + }); + hashKey = indexSpec.hashKey; + if (indexSpec.sortKey) { + index.KeySchema.push({ + AttributeName: indexSpec.sortKey, + KeyType: 'RANGE' + }); + requiredAttributes.push({ + AttributeName: indexSpec.sortKey, + AttributeType: attributeTypeFromSchema(indexName, schemaSource, indexSpec.sortKey) + }); + sortKey = indexSpec.sortKey; + } + } else { + throw new Error('Invalid index specification ${indexSpec}: must be 1,true, or {hashKey:"", sortKey?:""}.'); + } + indices.push({ + index, + requiredAttributes, + hashKey, + sortKey + }); + } + return indices; +}; + +const findPropertyValue = (object, value, duplicateErrMsg) => { + let r = null; + for (const [k, v] of Object.entries(object)) { + if (v === value) { + if (r === null) { + r = k; + } else { + throw new Error(duplicateErrMsg); + } + } + } + return r; +}; + +class Schema { + // Public fields: + name = ''; + idFieldName = ''; + typeFieldName = ''; + createdAtFieldName = ''; + updatedAtFieldName = ''; + source = null; + methods = Object.create(null); + statics = Object.create(null); + virtuals = Object.create(null); + converters = new Array(); + + // Protected fields: + [kSchemaCompiled] = null; + [kSchemaIndices] = []; + [kSchemaNewId] = null; + [kSchemaMarshall] = null; + [kSchemaUnMarshall] = null; + + constructor(name, schemaSource, options) { + const { index, generateId } = options ?? {}; + if (['object', 'undefined'].includes(typeof schemaSource) === false) { + throw new Error('Invalid schema: must be an object or undefined.'); + } + + schemaSource = schemaSource ?? {}; + const schemaSourceProps = schemaSource.properties ?? {}; + + if (!(name && (typeof name === 'string'))) { + throw new Error('Invalid name: must be a string.'); + } + this.name = name; + // TODO: since the id and type field names must be the same across the + // whole table, it would make sense to allow them to be specified in + // options (taking lower precedence than the values in the schema) + // extract the field names for fields with special meanings + this.idFieldName = findPropertyValue(schemaSourceProps, DocIdField, 'Duplicate id field.') || 'id'; + this.typeFieldName = findPropertyValue(schemaSourceProps, TypeField, 'Duplicate type field.') || 'type'; + this.createdAtFieldName = findPropertyValue(schemaSourceProps, CreatedAtField, 'Duplicate createdAt field.'); + this.updatedAtFieldName = findPropertyValue(schemaSourceProps, UpdatedAtField, 'Duplicate updatedAt field.'); + + if (schemaSource?.type && schemaSource?.type !== 'object') { + throw new Error('Schema type must be object (or can be omitted).'); + } + + const schemaProperties = Object.assign( + Object.create(null), + schemaSourceProps, + // ensure optional required fields are present in schema: + { + [this.idFieldName]: DocIdField, + [this.typeFieldName]: TypeField + } + ); + const schemaRequired = [...new Set([this.idFieldName, this.typeFieldName, ...(schemaSource?.required ?? [])])]; + + schemaSource = { + type: 'object', + properties: schemaProperties, + required: schemaRequired, + additionalProperties: schemaSource?.additionalProperties + }; + + this.source = schemaSource; + this[kSchemaCompiled] = ajv.compile(schemaSource); + this[kSchemaMarshall] = marshallingAjv.compile(schemaSource); + this[kSchemaUnMarshall] = unMarshallingAjv.compile(schemaSource); + this[kSchemaIndices] = parseIndexSpecification(index, schemaSource); + this[kSchemaNewId] = generateId ?? this.#generateDefaultId.bind(this); + } + + // Private methods: + #generateDefaultId() { + // TODO, generic model loading requires ids always to start with + // this.name + separator, a more generic compound-id api needs to + // require this? Or dynamic model loading should be scrapped? + return this.name + '.' + ObjectID(); + } +} + +// generate getter and setter functions for a Model's prototype from schema.virtuals: +function generateGettersAndSetters(schema) { + const descriptors = { }; + for (const [k,v] of Object.entries(schema.virtuals)) { + if (typeof v === 'string') { + // a simple aliased property, check that the aliased name exists: + if (!schema.source.properties[v]) { + throw new Error(`Virtual property "${k}" is an alias for an unknown property "${v}".`); + } + descriptors[k] = { + get() { + return this[v]; + }, + set(newValue) { + this[v] = newValue; + } + }; + } else if (typeof v === 'object') { + // otherwise we should have a data descriptor or accessor descriptor that should be passed to defineProperties directly: + for (const d of Object.keys(v)) { + if (['configurable', 'enumerable', 'value', 'writable', 'get', 'set'].indexOf(d) === -1) { + throw new Error(`Virtual property "${k}" invalid descriptor key "${d}" is not one of 'configurable', 'enumerable', 'value', 'writable', 'get' or 'set'.`); + } + } + descriptors[k] = Object.assign(Object.create(null), v); + // if we have a getter but no setter, add a setter which throws + if (descriptors[k].get && !descriptors[k].set) { + descriptors[k].set = function(){ + throw new Error(`Virtual property "${schema.name}.${k}" cannot be assigned.`); + }; + } + } else { + throw new Error(`Virtual property "${k}" must be a string alias, or a data descriptor or accessor descriptor.`); + } + } + return descriptors; +} + + +const createLogger = (loggingOptions) => { + if (loggingOptions){ + loggingOptions = (typeof loggingOptions === 'object')? loggingOptions : {}; + return require('pino')(loggingOptions); + } else { + const logger = require('abstract-logging'); + logger.child = () => logger; + return logger; + } +}; + +function DynamoDM(options) { + // global cross-table state: + const logger = createLogger(options?.logger); + const defaultOptions = Object.assign(Object.create(null), options, { logger }); + const PublicAPI = { + // Public API + // Create a schema, merging in default options: + Schema: (name, schemaSource, schemaOptions={}) => { + return new Schema(name, schemaSource, Object.assign(Object.create(null), defaultOptions, schemaOptions)); + }, + + // Create a table, merging in default options: + Table: (tableOptions={}) => { + return new Table(Object.assign(Object.create(null), defaultOptions, tableOptions)); + }, + + // Special Schema types + DocId, + Timestamp, + Binary, + + // Special Schema fields + DocIdField, + TypeField, + CreatedAtField, + UpdatedAtField, + }; + return PublicAPI; +} + +module.exports = DynamoDM; +module.exports.DynamoDM = DynamoDM; +module.exports.default = DynamoDM; + +// provide a helpful error message if someone forgets to call the API generator: +module.exports.Table = module.exports.Schema = function incorrectUsage(){ + throw new Error("DynamoDM must be called as a function to get an instance of the API, e.g. const DynamoDM = require('dynamodm')(options);"); +}; + +// export this for testing +DynamoDM.promiseAllWithCancellation = promiseAllWithCancellation; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..ad70183 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6984 @@ +{ + "name": "dynamodm", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "dynamodm", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-dynamodb": "^3.501.0", + "@aws-sdk/lib-dynamodb": "^3.501.0", + "abstract-logging": "^2.0.1", + "ajv": "^8.12.0", + "bson-objectid": "^2.0.4", + "pino": "^8.17.2" + }, + "devDependencies": { + "eslint": "^8.56.0", + "tap": "^18.7.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@alcalzone/ansi-tokenize": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.1.3.tgz", + "integrity": "sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=14.13.1" + } + }, + "node_modules/@alcalzone/ansi-tokenize/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@aws-crypto/crc32": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", + "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/ie11-detection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", + "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", + "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", + "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", + "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/util": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", + "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/util/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-sdk/client-dynamodb": { + "version": "3.501.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.501.0.tgz", + "integrity": "sha512-yPcxGnj6P87ye/mfTqwv3i29T3HO4eOGl2IBF8ZB5gQtOIctwg66TWBKCPG8HRbLKJgIVEvE20MiOELvuiUQVg==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.501.0", + "@aws-sdk/core": "3.496.0", + "@aws-sdk/credential-provider-node": "3.501.0", + "@aws-sdk/middleware-endpoint-discovery": "3.496.0", + "@aws-sdk/middleware-host-header": "3.496.0", + "@aws-sdk/middleware-logger": "3.496.0", + "@aws-sdk/middleware-recursion-detection": "3.496.0", + "@aws-sdk/middleware-user-agent": "3.496.0", + "@aws-sdk/region-config-resolver": "3.496.0", + "@aws-sdk/types": "3.496.0", + "@aws-sdk/util-endpoints": "3.496.0", + "@aws-sdk/util-user-agent-browser": "3.496.0", + "@aws-sdk/util-user-agent-node": "3.496.0", + "@smithy/config-resolver": "^2.1.1", + "@smithy/core": "^1.3.1", + "@smithy/fetch-http-handler": "^2.4.1", + "@smithy/hash-node": "^2.1.1", + "@smithy/invalid-dependency": "^2.1.1", + "@smithy/middleware-content-length": "^2.1.1", + "@smithy/middleware-endpoint": "^2.4.1", + "@smithy/middleware-retry": "^2.1.1", + "@smithy/middleware-serde": "^2.1.1", + "@smithy/middleware-stack": "^2.1.1", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/node-http-handler": "^2.3.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/url-parser": "^2.1.1", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.1", + "@smithy/util-defaults-mode-node": "^2.1.1", + "@smithy/util-endpoints": "^1.1.1", + "@smithy/util-middleware": "^2.1.1", + "@smithy/util-retry": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "@smithy/util-waiter": "^2.1.1", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.496.0.tgz", + "integrity": "sha512-fuaMuxKg7CMUsP9l3kxYWCOxFsBjdA0xj5nlikaDm1661/gB4KkAiGqRY8LsQkpNXvXU8Nj+f7oCFADFyGYzyw==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.496.0", + "@aws-sdk/middleware-host-header": "3.496.0", + "@aws-sdk/middleware-logger": "3.496.0", + "@aws-sdk/middleware-recursion-detection": "3.496.0", + "@aws-sdk/middleware-user-agent": "3.496.0", + "@aws-sdk/region-config-resolver": "3.496.0", + "@aws-sdk/types": "3.496.0", + "@aws-sdk/util-endpoints": "3.496.0", + "@aws-sdk/util-user-agent-browser": "3.496.0", + "@aws-sdk/util-user-agent-node": "3.496.0", + "@smithy/config-resolver": "^2.1.1", + "@smithy/core": "^1.3.1", + "@smithy/fetch-http-handler": "^2.4.1", + "@smithy/hash-node": "^2.1.1", + "@smithy/invalid-dependency": "^2.1.1", + "@smithy/middleware-content-length": "^2.1.1", + "@smithy/middleware-endpoint": "^2.4.1", + "@smithy/middleware-retry": "^2.1.1", + "@smithy/middleware-serde": "^2.1.1", + "@smithy/middleware-stack": "^2.1.1", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/node-http-handler": "^2.3.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/url-parser": "^2.1.1", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.1", + "@smithy/util-defaults-mode-node": "^2.1.1", + "@smithy/util-endpoints": "^1.1.1", + "@smithy/util-retry": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.501.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.501.0.tgz", + "integrity": "sha512-Uwc/xuxsA46dZS5s+4U703LBNDrGpWF7RB4XYEEMD21BLfGuqntxLLQux8xxKt3Pcur0CsXNja5jXt3uLnE5MA==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.496.0", + "@aws-sdk/credential-provider-node": "3.501.0", + "@aws-sdk/middleware-host-header": "3.496.0", + "@aws-sdk/middleware-logger": "3.496.0", + "@aws-sdk/middleware-recursion-detection": "3.496.0", + "@aws-sdk/middleware-user-agent": "3.496.0", + "@aws-sdk/region-config-resolver": "3.496.0", + "@aws-sdk/types": "3.496.0", + "@aws-sdk/util-endpoints": "3.496.0", + "@aws-sdk/util-user-agent-browser": "3.496.0", + "@aws-sdk/util-user-agent-node": "3.496.0", + "@smithy/config-resolver": "^2.1.1", + "@smithy/core": "^1.3.1", + "@smithy/fetch-http-handler": "^2.4.1", + "@smithy/hash-node": "^2.1.1", + "@smithy/invalid-dependency": "^2.1.1", + "@smithy/middleware-content-length": "^2.1.1", + "@smithy/middleware-endpoint": "^2.4.1", + "@smithy/middleware-retry": "^2.1.1", + "@smithy/middleware-serde": "^2.1.1", + "@smithy/middleware-stack": "^2.1.1", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/node-http-handler": "^2.3.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/url-parser": "^2.1.1", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.1", + "@smithy/util-defaults-mode-node": "^2.1.1", + "@smithy/util-endpoints": "^1.1.1", + "@smithy/util-middleware": "^2.1.1", + "@smithy/util-retry": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.496.0.tgz", + "integrity": "sha512-yT+ug7Cw/3eJi7x2es0+46x12+cIJm5Xv+GPWsrTFD1TKgqO/VPEgfDtHFagDNbFmjNQA65Ygc/kEdIX9ICX/A==", + "dependencies": { + "@smithy/core": "^1.3.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/signature-v4": "^2.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.496.0.tgz", + "integrity": "sha512-lukQMJ8SWWP5RqkRNOHi/H+WMhRvSWa3Fc5Jf/VP6xHiPLfF1XafcvthtV91e0VwPCiseI+HqChrcGq8pvnxHw==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/property-provider": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.501.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.501.0.tgz", + "integrity": "sha512-6UXnwLtYIr298ljveumCVXsH+x7csGscK5ylY+veRFy514NqyloRdJt8JY26hhh5SF9MYnkW+JyWSJ2Ls3tOjQ==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.496.0", + "@aws-sdk/credential-provider-process": "3.496.0", + "@aws-sdk/credential-provider-sso": "3.501.0", + "@aws-sdk/credential-provider-web-identity": "3.496.0", + "@aws-sdk/types": "3.496.0", + "@smithy/credential-provider-imds": "^2.2.1", + "@smithy/property-provider": "^2.1.1", + "@smithy/shared-ini-file-loader": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.501.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.501.0.tgz", + "integrity": "sha512-NM62D8gYrQ1nyLYwW4k48B2/lMHDzHDcQccS1wJakr6bg5sdtG06CumwlVcY+LAa0o1xRnhHmh/yiwj/nN4avw==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.496.0", + "@aws-sdk/credential-provider-ini": "3.501.0", + "@aws-sdk/credential-provider-process": "3.496.0", + "@aws-sdk/credential-provider-sso": "3.501.0", + "@aws-sdk/credential-provider-web-identity": "3.496.0", + "@aws-sdk/types": "3.496.0", + "@smithy/credential-provider-imds": "^2.2.1", + "@smithy/property-provider": "^2.1.1", + "@smithy/shared-ini-file-loader": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.496.0.tgz", + "integrity": "sha512-/YZscCTGOKVmGr916Th4XF8Sz6JDtZ/n2loHG9exok9iy/qIbACsTRNLP9zexPxhPoue/oZqecY5xbVljfY34A==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/property-provider": "^2.1.1", + "@smithy/shared-ini-file-loader": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.501.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.501.0.tgz", + "integrity": "sha512-y90dlvvZ55PwecODFdMx0NiNlJJfm7X6S61PKdLNCMRcu1YK+eWn0CmPHGHobBUQ4SEYhnFLcHSsf+VMim6BtQ==", + "dependencies": { + "@aws-sdk/client-sso": "3.496.0", + "@aws-sdk/token-providers": "3.501.0", + "@aws-sdk/types": "3.496.0", + "@smithy/property-provider": "^2.1.1", + "@smithy/shared-ini-file-loader": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.496.0.tgz", + "integrity": "sha512-IbP+qLlvJSpNPj+zW6TtFuLRTK5Tf0hW+2pom4vFyi5YSH4pn8UOC136UdewX8vhXGS9BJQ5zBDMasIyl5VeGQ==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/property-provider": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/endpoint-cache": { + "version": "3.495.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.495.0.tgz", + "integrity": "sha512-XCDrpiS50WaPzPzp7FwsChPHtX9PQQUU4nRzcn2N7IkUtpcFCUx8m1PAZe086VQr6hrbdeE4Z4j8hUPNwVdJGQ==", + "dependencies": { + "mnemonist": "0.38.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/lib-dynamodb": { + "version": "3.501.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.501.0.tgz", + "integrity": "sha512-2GJgPtHuRJto8bm87Kr/ztk/SJoLc0aOtUKA8v46izm5nnhUMx4M/wKZQjnuQXV8eWTxHQdDo00qDdOlubQ1NQ==", + "dependencies": { + "@aws-sdk/util-dynamodb": "3.501.0", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.0.0" + } + }, + "node_modules/@aws-sdk/middleware-endpoint-discovery": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.496.0.tgz", + "integrity": "sha512-VVJFTYeyhtjY8c0sAQUmzN4OUzaPINvXsYcL1dljFd7vdgSyf7+qwxzngOH5pKvyaCZ2vq9ngd8dAynSlA+TIg==", + "dependencies": { + "@aws-sdk/endpoint-cache": "3.495.0", + "@aws-sdk/types": "3.496.0", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.496.0.tgz", + "integrity": "sha512-jUdPpSJeqCYXf6hSjfwsfHway7peIV8Vz51w/BN91bF4vB/bYwAC5o9/iJiK/EoByp5asxA8fg9wFOyGjzdbLg==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/protocol-http": "^3.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.496.0.tgz", + "integrity": "sha512-EwMVSY6iBMeGbVnvwdaFl/ClMS/YWtxCAo+bcEtgk8ltRuo7qgbJem8Km/fvWC1vdWvIbe4ArdJ8iGzq62ffAw==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.496.0.tgz", + "integrity": "sha512-+IuOcFsfqg2WAnaEzH6KhVbicqCxtOq9w3DH2jwTpddRlCx2Kqf6wCzg8luhHRGyjBZdsbIS+OXwyMevoppawA==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/protocol-http": "^3.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.496.0.tgz", + "integrity": "sha512-+iMtRxFk0GmFWNUF4ilxylOQd9PZdR4ZC9jkcPIh1PZlvKtpCyFywKlk5RRZKklSoJ/CttcqwhMvOXTNbWm/0w==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@aws-sdk/util-endpoints": "3.496.0", + "@smithy/protocol-http": "^3.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.496.0.tgz", + "integrity": "sha512-URrNVOPHPgEDm6QFu6lDC2cUFs+Jx23mA3jEwCvoKlXiEY/ZoWjH8wlX3OMUlLrF1qoUTuD03jjrJzF6zoCgug==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/types": "^2.9.1", + "@smithy/util-config-provider": "^2.2.1", + "@smithy/util-middleware": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.501.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.501.0.tgz", + "integrity": "sha512-MvLPhNxlStmQqVm2crGLUqYWvK/AbMmI9j4FbEfJ15oG/I+730zjSJQEy2MvdiqbJRDPZ/tRCL89bUedOrmi0g==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.496.0", + "@aws-sdk/middleware-logger": "3.496.0", + "@aws-sdk/middleware-recursion-detection": "3.496.0", + "@aws-sdk/middleware-user-agent": "3.496.0", + "@aws-sdk/region-config-resolver": "3.496.0", + "@aws-sdk/types": "3.496.0", + "@aws-sdk/util-endpoints": "3.496.0", + "@aws-sdk/util-user-agent-browser": "3.496.0", + "@aws-sdk/util-user-agent-node": "3.496.0", + "@smithy/config-resolver": "^2.1.1", + "@smithy/fetch-http-handler": "^2.4.1", + "@smithy/hash-node": "^2.1.1", + "@smithy/invalid-dependency": "^2.1.1", + "@smithy/middleware-content-length": "^2.1.1", + "@smithy/middleware-endpoint": "^2.4.1", + "@smithy/middleware-retry": "^2.1.1", + "@smithy/middleware-serde": "^2.1.1", + "@smithy/middleware-stack": "^2.1.1", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/node-http-handler": "^2.3.1", + "@smithy/property-provider": "^2.1.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/shared-ini-file-loader": "^2.3.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/url-parser": "^2.1.1", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.1", + "@smithy/util-defaults-mode-node": "^2.1.1", + "@smithy/util-endpoints": "^1.1.1", + "@smithy/util-retry": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", + "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-dynamodb": { + "version": "3.501.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.501.0.tgz", + "integrity": "sha512-ywBTyScgHqtKJgpPjWW/63lNpRQ53rMkqLGLzcY2NQ6t2JJ2AREk+mZSMEGhUSddqO+zRk+k0uV4BSnLyHY0kQ==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.496.0.tgz", + "integrity": "sha512-1QzOiWHi383ZwqSi/R2KgKCd7M+6DxkxI5acqLPm8mvDRDP2jRjrnVaC0g9/tlttWousGEemDUWStwrD2mVYSw==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/types": "^2.9.1", + "@smithy/util-endpoints": "^1.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.495.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.495.0.tgz", + "integrity": "sha512-MfaPXT0kLX2tQaR90saBT9fWQq2DHqSSJRzW+MZWsmF+y5LGCOhO22ac/2o6TKSQm7h0HRc2GaADqYYYor62yg==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.496.0.tgz", + "integrity": "sha512-4j2spN+h0I0qfSMsGvJXTfQBu1e18rPdekKvzsGJxhaAE1tNgUfUT4nbvc5uVn0sNjZmirskmJ3kfbzVOrqIFg==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/types": "^2.9.1", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.496.0.tgz", + "integrity": "sha512-h0Ax0jlDc7UIo3KoSI4C4tVLBFoiAdx3+DhTVfgLS7x93d41dMlziPoBX2RgdcFn37qnzw6AQKTVTMwDbRCGpg==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@base2/pretty-print-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", + "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==", + "dev": true + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@eslint/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/ts-node-temp-fork-for-pr-2009": { + "version": "10.9.5", + "resolved": "https://registry.npmjs.org/@isaacs/ts-node-temp-fork-for-pr-2009/-/ts-node-temp-fork-for-pr-2009-10.9.5.tgz", + "integrity": "sha512-hEDlwpHhIabtB+Urku8muNMEkGui0LVGlYLS3KoB9QBDf0Pw3r7q0RrfoQmFuk8CvRpGzErO3/vLQd9Ys+/g4g==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node14": "*", + "@tsconfig/node16": "*", + "@tsconfig/node18": "*", + "@tsconfig/node20": "*", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=4.2" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/@isaacs/ts-node-temp-fork-for-pr-2009/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/agent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.0.tgz", + "integrity": "sha512-2yThA1Es98orMkpSLVqlDZAMPK3jHJhifP2gnNUdk1754uZ8yI5c+ulCoVG+WlntQA6MzhrURMXjSd9Z7dJ2/Q==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.4.tgz", + "integrity": "sha512-nr6/WezNzuYUppzXRaYu/W4aT5rLxdXqEFupbh6e/ovlYFQ8hpu1UUPV3Ir/YTl+74iXl2ZOMlGzudh9ZPUchQ==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dev": true, + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.0.0.tgz", + "integrity": "sha512-OI2zdYBLhQ7kpNPaJxiflofYIpkNLi+lnGdzqUOfRmCF3r2l1nadcjtCYMJKv/Utm/ZtlffaUuTiAktPHbc17g==", + "dev": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/package-json/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.1.tgz", + "integrity": "sha512-P4KkF9jX3y+7yFUxgcUdDtLy+t4OlDGuEBLNs57AZsfSfg+uV6MLndqGpnl4831ggaEdXwR50XFoZP4VFtHolg==", + "dev": true, + "dependencies": { + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", + "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sigstore/bundle": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.1.tgz", + "integrity": "sha512-v3/iS+1nufZdKQ5iAlQKcCsoh0jffQyABvYIxKsZQFWc4ubuGjwZklFHpDgV6O6T7vvV78SW5NHI91HFKEcxKg==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/core": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-0.2.0.tgz", + "integrity": "sha512-THobAPPZR9pDH2CAvDLpkrYedt7BlZnsyxDe+Isq4ZmGfPy5juOFZq487vCU2EgKD7aHSiTfE/i7sN7aEdzQnA==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", + "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.1.tgz", + "integrity": "sha512-U5sKQEj+faE1MsnLou1f4DQQHeFZay+V9s9768lw48J4pKykPj34rWyI1lsMOGJ3Mae47Ye6q3HAJvgXO21rkQ==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", + "@sigstore/protobuf-specs": "^0.2.1", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.0.tgz", + "integrity": "sha512-S98jo9cpJwO1mtQ+2zY7bOdcYyfVYCUaofCG6wWRzk3pxKHVAkSfshkfecto2+LKsx7Ovtqbgb2LS8zTRhxJ9Q==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.1", + "tuf-js": "^2.2.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/verify": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-0.1.0.tgz", + "integrity": "sha512-2UzMNYAa/uaz11NhvgRnIQf4gpLTJ59bhb8ESXaoSS5sxedfS+eLak8bsdMc+qpNQfITUTFoSKFx5h8umlRRiA==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", + "@sigstore/protobuf-specs": "^0.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.1.1.tgz", + "integrity": "sha512-1+qdrUqLhaALYL0iOcN43EP6yAXXQ2wWZ6taf4S2pNGowmOc5gx+iMQv+E42JizNJjB0+gEadOXeV1Bf7JWL1Q==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.1.1.tgz", + "integrity": "sha512-lxfLDpZm+AWAHPFZps5JfDoO9Ux1764fOgvRUBpHIO8HWHcSN1dkgsago1qLRVgm1BZ8RCm8cgv99QvtaOWIhw==", + "dependencies": { + "@smithy/node-config-provider": "^2.2.1", + "@smithy/types": "^2.9.1", + "@smithy/util-config-provider": "^2.2.1", + "@smithy/util-middleware": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-1.3.1.tgz", + "integrity": "sha512-tf+NIu9FkOh312b6M9G4D68is4Xr7qptzaZGZUREELF8ysE1yLKphqt7nsomjKZVwW7WE5pDDex9idowNGRQ/Q==", + "dependencies": { + "@smithy/middleware-endpoint": "^2.4.1", + "@smithy/middleware-retry": "^2.1.1", + "@smithy/middleware-serde": "^2.1.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/util-middleware": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.2.1.tgz", + "integrity": "sha512-7XHjZUxmZYnONheVQL7j5zvZXga+EWNgwEAP6OPZTi7l8J4JTeNh9aIOfE5fKHZ/ee2IeNOh54ZrSna+Vc6TFA==", + "dependencies": { + "@smithy/node-config-provider": "^2.2.1", + "@smithy/property-provider": "^2.1.1", + "@smithy/types": "^2.9.1", + "@smithy/url-parser": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.1.1.tgz", + "integrity": "sha512-E8KYBxBIuU4c+zrpR22VsVrOPoEDzk35bQR3E+xm4k6Pa6JqzkDOdMyf9Atac5GPNKHJBdVaQ4JtjdWX2rl/nw==", + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.9.1", + "@smithy/util-hex-encoding": "^2.1.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.4.1.tgz", + "integrity": "sha512-VYGLinPsFqH68lxfRhjQaSkjXM7JysUOJDTNjHBuN/ykyRb2f1gyavN9+VhhPTWCy32L4yZ2fdhpCs/nStEicg==", + "dependencies": { + "@smithy/protocol-http": "^3.1.1", + "@smithy/querystring-builder": "^2.1.1", + "@smithy/types": "^2.9.1", + "@smithy/util-base64": "^2.1.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.1.1.tgz", + "integrity": "sha512-Qhoq0N8f2OtCnvUpCf+g1vSyhYQrZjhSwvJ9qvR8BUGOtTXiyv2x1OD2e6jVGmlpC4E4ax1USHoyGfV9JFsACg==", + "dependencies": { + "@smithy/types": "^2.9.1", + "@smithy/util-buffer-from": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.1.1.tgz", + "integrity": "sha512-7WTgnKw+VPg8fxu2v9AlNOQ5yaz6RA54zOVB4f6vQuR0xFKd+RzlCpt0WidYTsye7F+FYDIaS/RnJW4pxjNInw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.1.1.tgz", + "integrity": "sha512-xozSQrcUinPpNPNPds4S7z/FakDTh1MZWtRP/2vQtYB/u3HYrX2UXuZs+VhaKBd6Vc7g2XPr2ZtwGBNDN6fNKQ==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.1.1.tgz", + "integrity": "sha512-rSr9ezUl9qMgiJR0UVtVOGEZElMdGFyl8FzWEF5iEKTlcWxGr2wTqGfDwtH3LAB7h+FPkxqv4ZU4cpuCN9Kf/g==", + "dependencies": { + "@smithy/protocol-http": "^3.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.4.1.tgz", + "integrity": "sha512-XPZTb1E2Oav60Ven3n2PFx+rX9EDsU/jSTA8VDamt7FXks67ekjPY/XrmmPDQaFJOTUHJNKjd8+kZxVO5Ael4Q==", + "dependencies": { + "@smithy/middleware-serde": "^2.1.1", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/shared-ini-file-loader": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/url-parser": "^2.1.1", + "@smithy/util-middleware": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.1.1.tgz", + "integrity": "sha512-eMIHOBTXro6JZ+WWzZWd/8fS8ht5nS5KDQjzhNMHNRcG5FkNTqcKpYhw7TETMYzbLfhO5FYghHy1vqDWM4FLDA==", + "dependencies": { + "@smithy/node-config-provider": "^2.2.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/service-error-classification": "^2.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/util-middleware": "^2.1.1", + "@smithy/util-retry": "^2.1.1", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.1.1.tgz", + "integrity": "sha512-D8Gq0aQBeE1pxf3cjWVkRr2W54t+cdM2zx78tNrVhqrDykRA7asq8yVJij1u5NDtKzKqzBSPYh7iW0svUKg76g==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.1.1.tgz", + "integrity": "sha512-KPJhRlhsl8CjgGXK/DoDcrFGfAqoqvuwlbxy+uOO4g2Azn1dhH+GVfC3RAp+6PoL5PWPb+vt6Z23FP+Mr6qeCw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.2.1.tgz", + "integrity": "sha512-epzK3x1xNxA9oJgHQ5nz+2j6DsJKdHfieb+YgJ7ATWxzNcB7Hc+Uya2TUck5MicOPhDV8HZImND7ZOecVr+OWg==", + "dependencies": { + "@smithy/property-provider": "^2.1.1", + "@smithy/shared-ini-file-loader": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.3.1.tgz", + "integrity": "sha512-gLA8qK2nL9J0Rk/WEZSvgin4AppvuCYRYg61dcUo/uKxvMZsMInL5I5ZdJTogOvdfVug3N2dgI5ffcUfS4S9PA==", + "dependencies": { + "@smithy/abort-controller": "^2.1.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/querystring-builder": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.1.1.tgz", + "integrity": "sha512-FX7JhhD/o5HwSwg6GLK9zxrMUrGnb3PzNBrcthqHKBc3dH0UfgEAU24xnJ8F0uow5mj17UeBEOI6o3CF2k7Mhw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.1.1.tgz", + "integrity": "sha512-6ZRTSsaXuSL9++qEwH851hJjUA0OgXdQFCs+VDw4tGH256jQ3TjYY/i34N4vd24RV3nrjNsgd1yhb57uMoKbzQ==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.1.1.tgz", + "integrity": "sha512-C/ko/CeEa8jdYE4gt6nHO5XDrlSJ3vdCG0ZAc6nD5ZIE7LBp0jCx4qoqp7eoutBu7VrGMXERSRoPqwi1WjCPbg==", + "dependencies": { + "@smithy/types": "^2.9.1", + "@smithy/util-uri-escape": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.1.1.tgz", + "integrity": "sha512-H4+6jKGVhG1W4CIxfBaSsbm98lOO88tpDWmZLgkJpt8Zkk/+uG0FmmqMuCAc3HNM2ZDV+JbErxr0l5BcuIf/XQ==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.1.1.tgz", + "integrity": "sha512-txEdZxPUgM1PwGvDvHzqhXisrc5LlRWYCf2yyHfvITWioAKat7srQvpjMAvgzf0t6t7j8yHrryXU9xt7RZqFpw==", + "dependencies": { + "@smithy/types": "^2.9.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.3.1.tgz", + "integrity": "sha512-2E2kh24igmIznHLB6H05Na4OgIEilRu0oQpYXo3LCNRrawHAcfDKq9004zJs+sAMt2X5AbY87CUCJ7IpqpSgdw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.1.1.tgz", + "integrity": "sha512-Hb7xub0NHuvvQD3YwDSdanBmYukoEkhqBjqoxo+bSdC0ryV9cTfgmNjuAQhTPYB6yeU7hTR+sPRiFMlxqv6kmg==", + "dependencies": { + "@smithy/eventstream-codec": "^2.1.1", + "@smithy/is-array-buffer": "^2.1.1", + "@smithy/types": "^2.9.1", + "@smithy/util-hex-encoding": "^2.1.1", + "@smithy/util-middleware": "^2.1.1", + "@smithy/util-uri-escape": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.3.1.tgz", + "integrity": "sha512-YsTdU8xVD64r2pLEwmltrNvZV6XIAC50LN6ivDopdt+YiF/jGH6PY9zUOu0CXD/d8GMB8gbhnpPsdrjAXHS9QA==", + "dependencies": { + "@smithy/middleware-endpoint": "^2.4.1", + "@smithy/middleware-stack": "^2.1.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/types": "^2.9.1", + "@smithy/util-stream": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.9.1.tgz", + "integrity": "sha512-vjXlKNXyprDYDuJ7UW5iobdmyDm6g8dDG+BFUncAg/3XJaN45Gy5RWWWUVgrzIK7S4R1KWgIX5LeJcfvSI24bw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.1.1.tgz", + "integrity": "sha512-qC9Bv8f/vvFIEkHsiNrUKYNl8uKQnn4BdhXl7VzQRP774AwIjiSMMwkbT+L7Fk8W8rzYVifzJNYxv1HwvfBo3Q==", + "dependencies": { + "@smithy/querystring-parser": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.1.1.tgz", + "integrity": "sha512-UfHVpY7qfF/MrgndI5PexSKVTxSZIdz9InghTFa49QOvuu9I52zLPLUHXvHpNuMb1iD2vmc6R+zbv/bdMipR/g==", + "dependencies": { + "@smithy/util-buffer-from": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.1.1.tgz", + "integrity": "sha512-ekOGBLvs1VS2d1zM2ER4JEeBWAvIOUKeaFch29UjjJsxmZ/f0L3K3x0dEETgh3Q9bkZNHgT+rkdl/J/VUqSRag==", + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.2.1.tgz", + "integrity": "sha512-/ggJG+ta3IDtpNVq4ktmEUtOkH1LW64RHB5B0hcr5ZaWBmo96UX2cIOVbjCqqDickTXqBWZ4ZO0APuaPrD7Abg==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.1.1.tgz", + "integrity": "sha512-clhNjbyfqIv9Md2Mg6FffGVrJxw7bgK7s3Iax36xnfVj6cg0fUG7I4RH0XgXJF8bxi+saY5HR21g2UPKSxVCXg==", + "dependencies": { + "@smithy/is-array-buffer": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.2.1.tgz", + "integrity": "sha512-50VL/tx9oYYcjJn/qKqNy7sCtpD0+s8XEBamIFo4mFFTclKMNp+rsnymD796uybjiIquB7VCB/DeafduL0y2kw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.1.1.tgz", + "integrity": "sha512-lqLz/9aWRO6mosnXkArtRuQqqZBhNpgI65YDpww4rVQBuUT7qzKbDLG5AmnQTCiU4rOquaZO/Kt0J7q9Uic7MA==", + "dependencies": { + "@smithy/property-provider": "^2.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.1.1.tgz", + "integrity": "sha512-tYVrc+w+jSBfBd267KDnvSGOh4NMz+wVH7v4CClDbkdPfnjvImBZsOURncT5jsFwR9KCuDyPoSZq4Pa6+eCUrA==", + "dependencies": { + "@smithy/config-resolver": "^2.1.1", + "@smithy/credential-provider-imds": "^2.2.1", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/property-provider": "^2.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.1.1.tgz", + "integrity": "sha512-sI4d9rjoaekSGEtq3xSb2nMjHMx8QXcz2cexnVyRWsy4yQ9z3kbDpX+7fN0jnbdOp0b3KSTZJZ2Yb92JWSanLw==", + "dependencies": { + "@smithy/node-config-provider": "^2.2.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.1.1.tgz", + "integrity": "sha512-3UNdP2pkYUUBGEXzQI9ODTDK+Tcu1BlCyDBaRHwyxhA+8xLP8agEKQq4MGmpjqb4VQAjq9TwlCQX0kP6XDKYLg==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.1.1.tgz", + "integrity": "sha512-mKNrk8oz5zqkNcbcgAAepeJbmfUW6ogrT2Z2gDbIUzVzNAHKJQTYmH9jcy0jbWb+m7ubrvXKb6uMjkSgAqqsFA==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.1.1.tgz", + "integrity": "sha512-Mg+xxWPTeSPrthpC5WAamJ6PW4Kbo01Fm7lWM1jmGRvmrRdsd3192Gz2fBXAMURyXpaNxyZf6Hr/nQ4q70oVEA==", + "dependencies": { + "@smithy/service-error-classification": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.1.1.tgz", + "integrity": "sha512-J7SMIpUYvU4DQN55KmBtvaMc7NM3CZ2iWICdcgaovtLzseVhAqFRYqloT3mh0esrFw+3VEK6nQFteFsTqZSECQ==", + "dependencies": { + "@smithy/fetch-http-handler": "^2.4.1", + "@smithy/node-http-handler": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-buffer-from": "^2.1.1", + "@smithy/util-hex-encoding": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.1.1.tgz", + "integrity": "sha512-saVzI1h6iRBUVSqtnlOnc9ssU09ypo7n+shdQ8hBTZno/9rZ3AuRYvoHInV57VF7Qn7B+pFJG7qTzFiHxWlWBw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.1.1.tgz", + "integrity": "sha512-BqTpzYEcUMDwAKr7/mVRUtHDhs6ZoXDi9NypMvMfOr/+u1NW7JgqodPDECiiLboEm6bobcPcECxzjtQh865e9A==", + "dependencies": { + "@smithy/util-buffer-from": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-waiter": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.1.1.tgz", + "integrity": "sha512-kYy6BLJJNif+uqNENtJqWdXcpqo1LS+nj1AfXcDhOpqpSHJSAkVySLyZV9fkmuVO21lzGoxjvd1imGGJHph/IA==", + "dependencies": { + "@smithy/abort-controller": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tapjs/after": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@tapjs/after/-/after-1.1.18.tgz", + "integrity": "sha512-r0vMFMfxmO6UR+pB9zGvamaeUI+yhLokYAagsKoM3JdoZgyq0iw1fHn5hPPY8AC1tAzEYG3KtVDpJfpoOr67Iw==", + "dev": true, + "dependencies": { + "is-actual-promise": "^1.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/after-each": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@tapjs/after-each/-/after-each-1.1.18.tgz", + "integrity": "sha512-AuXeD8uUYQ/CUdfhx2jvBhJf3M+T/Kroz5T6ItocZ3jf8H/4x2OKMVbb5YcB7J4ANGtmzXp+8SBseoN1av6y0Q==", + "dev": true, + "dependencies": { + "function-loop": "^4.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/asserts": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@tapjs/asserts/-/asserts-1.1.18.tgz", + "integrity": "sha512-MwGs/QklLRAsMnB4fO6QFaZ0myR//E21Rek/gGCpTxz7eUwCh24/y7MlBV0W6zDFdnQ1GFbHc/fIBVtcPAWjyw==", + "dev": true, + "dependencies": { + "@tapjs/stack": "1.2.7", + "is-actual-promise": "^1.0.0", + "tcompare": "6.4.5", + "trivial-deferred": "^2.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/before": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@tapjs/before/-/before-1.1.18.tgz", + "integrity": "sha512-2rkXrAWlkl0+bZ8wSNfEW/7TANs/Dg5SrY2MmdEb0x7Q/zbMoGjrPVKDRF20Me0p+tJBLWSY+FXQ0OhXK0pUjg==", + "dev": true, + "dependencies": { + "is-actual-promise": "^1.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/before-each": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@tapjs/before-each/-/before-each-1.1.18.tgz", + "integrity": "sha512-qxBQaOY+IkThP9iauL1tHCxirG9XuKGJvGHY4IGKuk0RswWkXmawSe5hcJ8m569dRXy9yJHEV7N0QueuyWxpBA==", + "dev": true, + "dependencies": { + "function-loop": "^4.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/config": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@tapjs/config/-/config-2.4.15.tgz", + "integrity": "sha512-uU/gfQJh8aSokEBgwAAHD5ctHYbIiZYFaL6IrROcDp7Wr7/fd/dn9K4efpREwKpqKqOgL3XZPOwx7prKxrLHhA==", + "dev": true, + "dependencies": { + "@tapjs/core": "1.5.0", + "@tapjs/test": "1.4.0", + "chalk": "^5.2.0", + "jackspeak": "^2.3.6", + "polite-json": "^4.0.1", + "tap-yaml": "2.2.1", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0", + "@tapjs/test": "1.4.0" + } + }, + "node_modules/@tapjs/config/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@tapjs/core": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@tapjs/core/-/core-1.5.0.tgz", + "integrity": "sha512-g+NNI5TGXVJR5G4AZCU0hWu1pdA2qB2OYrY9Ej3mWeg97mvNZBVgNtvx8Vjdwp9BfgbJfyFK7PvoB4nhKgetSQ==", + "dev": true, + "dependencies": { + "@tapjs/processinfo": "^3.1.6", + "@tapjs/stack": "1.2.7", + "@tapjs/test": "1.4.0", + "async-hook-domain": "^4.0.1", + "diff": "^5.1.0", + "is-actual-promise": "^1.0.0", + "minipass": "^7.0.3", + "signal-exit": "4.1", + "tap-parser": "15.3.1", + "tap-yaml": "2.2.1", + "tcompare": "6.4.5", + "trivial-deferred": "^2.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + } + }, + "node_modules/@tapjs/error-serdes": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@tapjs/error-serdes/-/error-serdes-1.2.1.tgz", + "integrity": "sha512-/7eLEcrGo+Qz3eWrjkhDC+VSEOjabkkzr9eRADeU+OLFeZaik8L/GRk0SGhnp4YsQkv0jcNV00A42bEx2HIZcw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/filter": { + "version": "1.2.18", + "resolved": "https://registry.npmjs.org/@tapjs/filter/-/filter-1.2.18.tgz", + "integrity": "sha512-0yCqaHYLejI/KyxdB5EsrRVu3wxZVl7vPXTwBoyc+ycJWXPapHLhKl67Xk5x3FW/nNelA9TCq/tSHcYlogGN0g==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/fixture": { + "version": "1.2.18", + "resolved": "https://registry.npmjs.org/@tapjs/fixture/-/fixture-1.2.18.tgz", + "integrity": "sha512-BQIRxydaqjZIG61QhoiQOc9HE3MxSjCn7SUsIfYCzoZoY+3aY6iCdTVg2la86b5ikTbwoWxWWbqICnFWebuHnQ==", + "dev": true, + "dependencies": { + "mkdirp": "^3.0.0", + "rimraf": "^5.0.5" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/fixture/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tapjs/fixture/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/fixture/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/fixture/node_modules/rimraf": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/intercept": { + "version": "1.2.18", + "resolved": "https://registry.npmjs.org/@tapjs/intercept/-/intercept-1.2.18.tgz", + "integrity": "sha512-Trcmp64RKD2/nMz7/+NuwjJHfrn8eFofX3s3g0+QGvnTv+5B5ZQs+zWjS7q2d1Qt8LDV8CfS5w3BhYyONsocSw==", + "dev": true, + "dependencies": { + "@tapjs/after": "1.1.18", + "@tapjs/stack": "1.2.7" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/mock": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tapjs/mock/-/mock-1.3.0.tgz", + "integrity": "sha512-Uzyikl8SS8Mg7OOr2HuyiaVhYvHNRZnw6A1/qTiJnoZ1MHcLFuwFqIX9ZhfXMil5MIYC/ET096VMDm45q9Tdvw==", + "dev": true, + "dependencies": { + "@tapjs/after": "1.1.18", + "@tapjs/stack": "1.2.7", + "resolve-import": "^1.4.5", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/node-serialize": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tapjs/node-serialize/-/node-serialize-1.3.0.tgz", + "integrity": "sha512-52oQKQJMMKrI1cNu8kJ5WTv8YFnbhwfwUs3Jh1vXQb4tOhLW8IHWqXBi5AiNL3HlCMMHaKDFQjW6sbbJuMyJPA==", + "dev": true, + "dependencies": { + "@tapjs/error-serdes": "1.2.1", + "@tapjs/stack": "1.2.7", + "tap-parser": "15.3.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/processinfo": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@tapjs/processinfo/-/processinfo-3.1.6.tgz", + "integrity": "sha512-ktDsaf79wJsLaoG1Pp+stHSRf6a1k/JydoRAaYVG5iJnd3DooL6yewZsciUi2yiN/WQc5tAXCIFTXL4uXGB8LA==", + "dev": true, + "dependencies": { + "pirates": "^4.0.5", + "process-on-spawn": "^1.0.0", + "signal-exit": "^4.0.2", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=16.17" + } + }, + "node_modules/@tapjs/reporter": { + "version": "1.3.16", + "resolved": "https://registry.npmjs.org/@tapjs/reporter/-/reporter-1.3.16.tgz", + "integrity": "sha512-YoZpBAFGdZyrhIaRCZDuWSeCc10A3YG/4mIdPsKpSbLXPBZ1hwCV8Y/LPCpH5kunZTXYocvQoRHU+oD4pLXC3g==", + "dev": true, + "dependencies": { + "@tapjs/config": "2.4.15", + "@tapjs/stack": "1.2.7", + "chalk": "^5.2.0", + "ink": "^4.4.1", + "minipass": "^7.0.3", + "ms": "^2.1.3", + "patch-console": "^2.0.0", + "prismjs-terminal": "^1.2.3", + "react": "^18.2.0", + "string-length": "^6.0.0", + "tap-parser": "15.3.1", + "tap-yaml": "2.2.1", + "tcompare": "6.4.5" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/reporter/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@tapjs/reporter/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/@tapjs/run": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@tapjs/run/-/run-1.5.0.tgz", + "integrity": "sha512-WrmbHHrhvRvLlTTAGiogF09xiPoorsoG4diAIKifGUyGD/9qRA7pT2mzYIqXvhyxbtuEmaeobHjupSZrak+O4Q==", + "dev": true, + "dependencies": { + "@tapjs/after": "1.1.18", + "@tapjs/before": "1.1.18", + "@tapjs/config": "2.4.15", + "@tapjs/processinfo": "^3.1.6", + "@tapjs/reporter": "1.3.16", + "@tapjs/spawn": "1.1.18", + "@tapjs/stdin": "1.1.18", + "@tapjs/test": "1.4.0", + "c8": "^8.0.1", + "chalk": "^5.3.0", + "chokidar": "^3.5.3", + "foreground-child": "^3.1.1", + "glob": "^10.3.10", + "minipass": "^7.0.3", + "mkdirp": "^3.0.1", + "opener": "^1.5.2", + "pacote": "^17.0.3", + "resolve-import": "^1.4.5", + "rimraf": "^5.0.5", + "semver": "^7.5.4", + "signal-exit": "^4.1.0", + "tap-parser": "15.3.1", + "tap-yaml": "2.2.1", + "tcompare": "6.4.5", + "trivial-deferred": "^2.0.0", + "which": "^4.0.0" + }, + "bin": { + "tap-run": "dist/esm/index.js" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/run/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tapjs/run/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@tapjs/run/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/run/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@tapjs/run/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/run/node_modules/rimraf": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/run/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tapjs/snapshot": { + "version": "1.2.18", + "resolved": "https://registry.npmjs.org/@tapjs/snapshot/-/snapshot-1.2.18.tgz", + "integrity": "sha512-fHt4ZgutJ922/YdmXN2d6dkwFTR6KsyD02jcSYBXVDGdFC2YnsjKk/o9s3Yt9tYnYES6Et+6udPlAKcakzR5jQ==", + "dev": true, + "dependencies": { + "is-actual-promise": "^1.0.0", + "tcompare": "6.4.5", + "trivial-deferred": "^2.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/spawn": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@tapjs/spawn/-/spawn-1.1.18.tgz", + "integrity": "sha512-E5H0NTyTZ0FnkPUd5JU3c2KrnjjMDDAuctRd2b0v/M5LB+uAlwwEEJJ6rh+dBsFK/yatfgPli+nbHZVjUz+Usw==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/stack": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@tapjs/stack/-/stack-1.2.7.tgz", + "integrity": "sha512-7qUDWDmd+y7ZQ0vTrDTvFlWnJ+ND32NemS5HVuT1ZggHtBwJ62PQHIyCx/B5RopETBb6NvFPfUE21yTiex9Jkw==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/stdin": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@tapjs/stdin/-/stdin-1.1.18.tgz", + "integrity": "sha512-UyhK8bRRhQkmBb7N/NFa/11DucHfIzCyyba7uax+dkuXSd6OccTZVxLpRMuaOUV59QCCFAJUJDQnmaWj35fI7Q==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/test": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@tapjs/test/-/test-1.4.0.tgz", + "integrity": "sha512-t4U11uAUDUeBQTdlqtiDoiuiG3lKLhHa+PxrdIR3GlG+2wDcpqFR8aFFiuq3XTvks0uoWjKx3WkAMyjNsxmikg==", + "dev": true, + "dependencies": { + "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.5", + "@tapjs/after": "1.1.18", + "@tapjs/after-each": "1.1.18", + "@tapjs/asserts": "1.1.18", + "@tapjs/before": "1.1.18", + "@tapjs/before-each": "1.1.18", + "@tapjs/filter": "1.2.18", + "@tapjs/fixture": "1.2.18", + "@tapjs/intercept": "1.2.18", + "@tapjs/mock": "1.3.0", + "@tapjs/node-serialize": "1.3.0", + "@tapjs/snapshot": "1.2.18", + "@tapjs/spawn": "1.1.18", + "@tapjs/stdin": "1.1.18", + "@tapjs/typescript": "1.4.0", + "@tapjs/worker": "1.1.18", + "glob": "^10.3.10", + "jackspeak": "^2.3.6", + "mkdirp": "^3.0.0", + "resolve-import": "^1.4.5", + "rimraf": "^5.0.5", + "sync-content": "^1.0.1", + "tap-parser": "15.3.1", + "tshy": "^1.2.2", + "typescript": "5.2" + }, + "bin": { + "generate-tap-test-class": "scripts/build.mjs" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/test/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tapjs/test/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/test/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/test/node_modules/rimraf": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/typescript": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@tapjs/typescript/-/typescript-1.4.0.tgz", + "integrity": "sha512-3b3pNI20Cf9NRMuT6GE288RESMYMcrwrKuj29Mroiy9MkLEyyPPHqeSRstvakn9/i/nhTlXj2YIftPo80H3OlQ==", + "dev": true, + "dependencies": { + "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.5" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tapjs/worker": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@tapjs/worker/-/worker-1.1.18.tgz", + "integrity": "sha512-wxl/dXByMWk9FuYiiSzY/U5QU0oe9EWpf7pJ48feWsTTn42wihUHZT25kbleR4V2l68/SlTPlJkEsKnHjU27Pg==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.0" + } + }, + "node_modules/@tsconfig/node14": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-14.1.0.tgz", + "integrity": "sha512-VmsCG04YR58ciHBeJKBDNMWWfYbyP8FekWVuTlpstaUPlat1D0x/tXzkWP7yCMU0eSz9V4OZU0LBWTFJ3xZf6w==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-16.1.1.tgz", + "integrity": "sha512-+pio93ejHN4nINX4pXqfnR/fPLRtJBaT4ORaa5RH0Oc1zoYmo2B2koG+M328CQhHKn1Wj6FcOxCDFXAot9NhvA==", + "dev": true + }, + "node_modules/@tsconfig/node18": { + "version": "18.2.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.2.tgz", + "integrity": "sha512-d6McJeGsuoRlwWZmVIeE8CUA27lu6jLjvv1JzqmpsytOYYbVi1tHZEnwCNVOXnj4pyLvneZlFlpXUK+X9wBWyw==", + "dev": true + }, + "node_modules/@tsconfig/node20": { + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node20/-/node20-20.1.2.tgz", + "integrity": "sha512-madaWq2k+LYMEhmcp0fs+OGaLFk0OenpHa4gmI4VEmCKX4PJntQ6fnnGADVFrVkBj0wIdAlQnK/MrlYTHsa1gQ==", + "dev": true + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.0.tgz", + "integrity": "sha512-c8nj8BaOExmZKO2DXhDfegyhSGcG9E/mPN3U13L+/PsoWm1uaGiHHjxqSHQiasDBQwDA3aHuw9+9spYAP1qvvg==", + "dev": true, + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.11.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.10.tgz", + "integrity": "sha512-rZEfe/hJSGYmdfX9tvcPMYeYPW2sNl50nsw4jZmRcaG0HIAb0WYEpsB05GOb53vjqpyE9GUhlDQ4jLSoB5q9kg==", + "dev": true, + "peer": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/abstract-logging": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==" + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aggregate-error/node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", + "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", + "dev": true, + "dependencies": { + "type-fest": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/async-hook-domain": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/async-hook-domain/-/async-hook-domain-4.0.1.tgz", + "integrity": "sha512-bSktexGodAjfHWIrSrrqxqWzf1hWBZBpmPNZv+TYUMyWa2eoefFc6q6H1+KtdHYSz35lrhWdmXt/XK9wNEZvww==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/auto-bind": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-5.0.1.tgz", + "integrity": "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bson-objectid": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/bson-objectid/-/bson-objectid-2.0.4.tgz", + "integrity": "sha512-vgnKAUzcDoa+AeyYwXCoHyF2q6u/8H46dxu5JN+4/TZeq/Dlinn0K6GvxsCLb3LHUJl0m/TLiEK31kUwtgocMQ==" + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/c8": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/c8/-/c8-8.0.1.tgz", + "integrity": "sha512-EINpopxZNH1mETuI0DzRA4MZpAUH+IFiRhnmFD3vFr3vdrgxqi3VfE3KL0AIL+zDq8rC9bZqwM/VDmmoe04y7w==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "rimraf": "^3.0.2", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/c8/node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/c8/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/cacache": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", + "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/code-excerpt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", + "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==", + "dev": true, + "dependencies": { + "convert-to-spaces": "^2.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/convert-to-spaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", + "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/events-to-array": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-2.0.3.tgz", + "integrity": "sha512-f/qE2gImHRa4Cp2y1stEOSgw8wTFyUdVJX7G//bMwbaV9JqISFxg99NbmVQeP7YLnDUZ2un851jlaDrlpmGehQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-redact": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.3.0.tgz", + "integrity": "sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-xml-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", + "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", + "funding": [ + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + }, + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.0.tgz", + "integrity": "sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function-loop": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/function-loop/-/function-loop-4.0.0.tgz", + "integrity": "sha512-f34iQBedYF3XcI93uewZZOnyscDragxgTK/eTvVB74k3fCD0ZorOi5BV9GS4M8rz/JoNi0Kl3qX5Y9MH3S/CLQ==", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", + "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", + "dev": true, + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ink": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/ink/-/ink-4.4.1.tgz", + "integrity": "sha512-rXckvqPBB0Krifk5rn/5LvQGmyXwCUpBfmTwbkQNBY9JY8RSl3b8OftBNEYxg4+SWUhEKcPifgope28uL9inlA==", + "dev": true, + "dependencies": { + "@alcalzone/ansi-tokenize": "^0.1.3", + "ansi-escapes": "^6.0.0", + "auto-bind": "^5.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "cli-cursor": "^4.0.0", + "cli-truncate": "^3.1.0", + "code-excerpt": "^4.0.0", + "indent-string": "^5.0.0", + "is-ci": "^3.0.1", + "is-lower-case": "^2.0.2", + "is-upper-case": "^2.0.2", + "lodash": "^4.17.21", + "patch-console": "^2.0.0", + "react-reconciler": "^0.29.0", + "scheduler": "^0.23.0", + "signal-exit": "^3.0.7", + "slice-ansi": "^6.0.0", + "stack-utils": "^2.0.6", + "string-width": "^5.1.2", + "type-fest": "^0.12.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0", + "ws": "^8.12.0", + "yoga-wasm-web": "~0.3.3" + }, + "engines": { + "node": ">=14.16" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "react": ">=18.0.0", + "react-devtools-core": "^4.19.1" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react-devtools-core": { + "optional": true + } + } + }, + "node_modules/ink/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ink/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/ink/node_modules/type-fest": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz", + "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "node_modules/is-actual-promise": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-actual-promise/-/is-actual-promise-1.0.1.tgz", + "integrity": "sha512-PlsL4tNv62lx5yN2HSqaRSTgIpUAPW7U6+crVB8HfWm5161rZpeqWbl0ZSqH2MAfRKXWSZVPRNbE/r8qPcb13g==", + "dev": true, + "dependencies": { + "tshy": "^1.7.0" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "node_modules/is-lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-2.0.2.tgz", + "integrity": "sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-upper-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-2.0.2.tgz", + "integrity": "sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "dev": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mnemonist": { + "version": "0.38.3", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.3.tgz", + "integrity": "sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw==", + "dependencies": { + "obliterator": "^1.6.1" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-gyp": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", + "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/node-gyp/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/node-gyp/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/nopt": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", + "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "dev": true, + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", + "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", + "dev": true, + "dependencies": { + "ignore-walk": "^6.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz", + "integrity": "sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==", + "dev": true, + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.1.0.tgz", + "integrity": "sha512-PQCELXKt8Azvxnt5Y85GseQDJJlglTFM9L9U9gkv2y4e9s0k3GVDdOx3YoB6gm2Do0hlkzC39iCGXby+Wve1Bw==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/obliterator": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-1.6.1.tgz", + "integrity": "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==" + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pacote": { + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz", + "integrity": "sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==", + "dev": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/patch-console": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/patch-console/-/patch-console-2.0.0.tgz", + "integrity": "sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "8.17.2", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.17.2.tgz", + "integrity": "sha512-LA6qKgeDMLr2ux2y/YiUt47EfgQ+S9LznBWOJdN3q1dx2sv0ziDLUBeVpyVv17TEcGCBuWf0zNtg3M5m1NhhWQ==", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "v1.1.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^3.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.7.0", + "thread-stream": "^2.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.1.0.tgz", + "integrity": "sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==", + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", + "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==" + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/polite-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/polite-json/-/polite-json-4.0.1.tgz", + "integrity": "sha512-8LI5ZeCPBEb4uBbcYKNVwk4jgqNx1yHReWoW4H4uUihWlSqZsUDfSITrRhjliuPgxsNPFhNSudGO2Zu4cbWinQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/prismjs-terminal": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prismjs-terminal/-/prismjs-terminal-1.2.3.tgz", + "integrity": "sha512-xc0zuJ5FMqvW+DpiRkvxURlz98DdfDsZcFHdO699+oL+ykbFfgI7O4VDEgUyc07BSL2NHl3zdb8m/tZ/aaqUrw==", + "dev": true, + "dependencies": { + "chalk": "^5.2.0", + "prismjs": "^1.29.0", + "string-length": "^6.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/prismjs-terminal/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==" + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dev": true, + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-element-to-jsx-string": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-15.0.0.tgz", + "integrity": "sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==", + "dev": true, + "dependencies": { + "@base2/pretty-print-object": "1.0.1", + "is-plain-object": "5.0.0", + "react-is": "18.1.0" + }, + "peerDependencies": { + "react": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", + "react-dom": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0" + } + }, + "node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/react-reconciler": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz", + "integrity": "sha512-wa0fGj7Zht1EYMRhKWwoo1H9GApxYLBuhoAuXN0TlltESAjDssB+Apf0T/DngVqaMyPypDmabL37vw/2aRM98Q==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/read-package-json": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.0.tgz", + "integrity": "sha512-uL4Z10OKV4p6vbdvIXB+OzhInYtIozl/VxUBPgNkBuUi2DeRonnuspmaVAMcrkmfjKGNmRndyQAbE7/AmzGwFg==", + "dev": true, + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/read-package-json/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/read-package-json/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-import": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/resolve-import/-/resolve-import-1.4.5.tgz", + "integrity": "sha512-HXb4YqODuuXT7Icq1Z++0g2JmhgbUHSs3VT2xR83gqvAPUikYT2Xk+562KHQgiaNkbBOlPddYrDLsC44qQggzw==", + "dev": true, + "dependencies": { + "glob": "^10.3.3", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/resolve-import/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/resolve-import/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/resolve-import/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "optional": true + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sigstore": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.2.0.tgz", + "integrity": "sha512-fcU9clHwEss2/M/11FFM8Jwc4PjBgbhXoNskoK5guoK0qGQBSeUbQZRJ+B2fDFIvhyf0gqCaPrel9mszbhAxug==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", + "@sigstore/protobuf-specs": "^0.2.1", + "@sigstore/sign": "^2.2.1", + "@sigstore/tuf": "^2.3.0", + "@sigstore/verify": "^0.1.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/slice-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-6.0.0.tgz", + "integrity": "sha512-6bn4hRfkTvDfUoEQYkERg0BVF1D0vrX9HEkMl08uDiNWvVvjylLHvZFZWkDo6wjT8tUctbYl1nCOuE66ZTaUtA==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", + "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/sonic-boom": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.0.tgz", + "integrity": "sha512-ybz6OYOUjoQQCQ/i4LU8kaToD8ACtYP+Cj5qd2AO36bwbdewxWJ3ArmJ2cr6AvxlL2o0PqnCcPGUgkILbfkaCA==", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz", + "integrity": "sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-6.0.0.tgz", + "integrity": "sha512-1U361pxZHEQ+FeSjzqRpV+cu2vTzYeWeafXFLykiFlv4Vc0n3njgU8HrMbyik5uwm77naWMuVG8fhEF+Ovb1Kg==", + "dev": true, + "dependencies": { + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sync-content": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/sync-content/-/sync-content-1.0.2.tgz", + "integrity": "sha512-znd3rYiiSxU3WteWyS9a6FXkTA/Wjk8WQsOyzHbineeL837dLn3DA4MRhsIX3qGcxDMH6+uuFV4axztssk7wEQ==", + "dev": true, + "dependencies": { + "glob": "^10.2.6", + "mkdirp": "^3.0.1", + "path-scurry": "^1.9.2", + "rimraf": "^5.0.1" + }, + "bin": { + "sync-content": "dist/mjs/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sync-content/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/sync-content/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sync-content/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sync-content/node_modules/rimraf": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tap": { + "version": "18.7.0", + "resolved": "https://registry.npmjs.org/tap/-/tap-18.7.0.tgz", + "integrity": "sha512-bL/0krlx8k3fY9mjI9CMfVoAGclZegl+vm5pEJpF/USxam5eNhp5wLk5UH0ST3gWEJkW0PDdFHTOStE+mYurrQ==", + "dev": true, + "dependencies": { + "@tapjs/after": "1.1.18", + "@tapjs/after-each": "1.1.18", + "@tapjs/asserts": "1.1.18", + "@tapjs/before": "1.1.18", + "@tapjs/before-each": "1.1.18", + "@tapjs/core": "1.5.0", + "@tapjs/filter": "1.2.18", + "@tapjs/fixture": "1.2.18", + "@tapjs/intercept": "1.2.18", + "@tapjs/mock": "1.3.0", + "@tapjs/node-serialize": "1.3.0", + "@tapjs/run": "1.5.0", + "@tapjs/snapshot": "1.2.18", + "@tapjs/spawn": "1.1.18", + "@tapjs/stdin": "1.1.18", + "@tapjs/test": "1.4.0", + "@tapjs/typescript": "1.4.0", + "@tapjs/worker": "1.1.18", + "resolve-import": "^1.4.5" + }, + "bin": { + "tap": "dist/esm/run.mjs" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tap-parser": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-15.3.1.tgz", + "integrity": "sha512-hwAtXX5TBGt2MJeYvASc7DjP48PUzA7P8RTbLxQcgKCEH7ICD5IsRco7l5YvkzjHlZbUbeI9wzO8B4hw2sKgnQ==", + "dev": true, + "dependencies": { + "events-to-array": "^2.0.3", + "tap-yaml": "2.2.1" + }, + "bin": { + "tap-parser": "bin/cmd.cjs" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + } + }, + "node_modules/tap-yaml": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-2.2.1.tgz", + "integrity": "sha512-ovZuUMLAIH59jnFHXKEGJ+WyDYl6Cuduwg9qpvnqkZOUA1nU84q02Sry1HT0KXcdv2uB91bEKKxnIybBgrb6oA==", + "dev": true, + "dependencies": { + "yaml": "^2.3.0", + "yaml-types": "^0.3.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + } + }, + "node_modules/tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tcompare": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-6.4.5.tgz", + "integrity": "sha512-Whuz9xlKKI2XXICKDSDRKjXdBuC6gBNOgmEUtH7UFyQeYzfUMQ19DyjZULarGKDGFhgOg3CJ+IQUEfpkOPg0Uw==", + "dev": true, + "dependencies": { + "diff": "^5.1.0", + "react-element-to-jsx-string": "^15.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/thread-stream": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.4.1.tgz", + "integrity": "sha512-d/Ex2iWd1whipbT681JmTINKw0ZwOUBZm7+Gjs64DHuX34mmw8vJL2bFAaNacaW72zYiTJxSHi5abUuOi5nsfg==", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/trivial-deferred": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-2.0.0.tgz", + "integrity": "sha512-iGbM7X2slv9ORDVj2y2FFUq3cP/ypbtu2nQ8S38ufjL0glBABvmR9pTdsib1XtS2LUhhLMbelaBUaf/s5J3dSw==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tshy": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/tshy/-/tshy-1.11.0.tgz", + "integrity": "sha512-5T5PVyuYQKTcOKz5a2lpwx4WKi8yEzQGO0Q5l+9clJMYupMaTI7ONEwKggGAZDQQGIgCOyUCfBWnSkG0XdJc+A==", + "dev": true, + "dependencies": { + "chalk": "^5.3.0", + "chokidar": "^3.5.3", + "foreground-child": "^3.1.1", + "mkdirp": "^3.0.1", + "resolve-import": "^1.4.4", + "rimraf": "^5.0.1", + "sync-content": "^1.0.2", + "typescript": "5.2 || 5.3", + "walk-up-path": "^3.0.1" + }, + "bin": { + "tshy": "dist/esm/index.js" + }, + "engines": { + "node": "16 >=16.17 || 18 >=18.15.0 || >=20.6.1" + } + }, + "node_modules/tshy/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/tshy/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/tshy/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tshy/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tshy/node_modules/rimraf": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/tuf-js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.0.tgz", + "integrity": "sha512-ZSDngmP1z6zw+FIkIBjvOp/II/mIub/O7Pp12j1WNsiCpg5R5wAc//i555bBQsE44O94btLt0xM/Zr2LQjwdCg==", + "dev": true, + "dependencies": { + "@tufjs/models": "2.0.0", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "peer": true + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/walk-up-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", + "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dev": true, + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yaml-types": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yaml-types/-/yaml-types-0.3.0.tgz", + "integrity": "sha512-i9RxAO/LZBiE0NJUy9pbN5jFz5EasYDImzRkj8Y81kkInTi1laia3P3K/wlMKzOxFQutZip8TejvQP/DwgbU7A==", + "dev": true, + "engines": { + "node": ">= 16", + "npm": ">= 7" + }, + "peerDependencies": { + "yaml": "^2.3.0" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoga-wasm-web": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz", + "integrity": "sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..390a8eb --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "dynamodm", + "version": "1.0.0", + "description": "Simple Document mapper for DynamoDB, inspired by mongoose.", + "main": "index.js", + "scripts": { + "test": "tap run --show-full-coverage --allow-incomplete-coverage", + "lint": "./node_modules/.bin/eslint -c .eslintrc.json './{,!(node_modules)/**/}*.js'" + }, + "keywords": [ + "dynamodb", + "dynamodb-doc-client", + "dynamo", + "document", + "mapper", + "mongoose" + ], + "dependencies": { + "@aws-sdk/client-dynamodb": "^3.501.0", + "@aws-sdk/lib-dynamodb": "^3.501.0", + "abstract-logging": "^2.0.1", + "ajv": "^8.12.0", + "bson-objectid": "^2.0.4", + "pino": "^8.17.2" + }, + "author": "James Crosby <3456211+autopulated@users.noreply.github.com>", + "license": "Apache-2.0", + "devDependencies": { + "eslint": "^8.56.0", + "tap": "^18.7.0" + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..29f9a95 --- /dev/null +++ b/readme.md @@ -0,0 +1,72 @@ +## DynamoDM: Simple Document Mapper for DynamoDB + +## Quickstart: +``` +const DynamoDM = require('dynamodm')(); + +const table = DynamoDM.Table('my-dynamodb-table'); + +// Create a User model with a JSON schema: +const UserModel = table.model(DynamoDM.Schema('user', { + properties: { + // Identify the id field using the built-in schema. Every model in the same table must share the same id field name: + id: DynamoDM.DocIdField, + emailAddress: {type: 'string'}, + marketingComms: {type: 'boolean', default: false} + }, +})); +// and a Comment model: +const CommentModel = table.model(DynamoDM.Schema('c', { + properties: { + id: DynamoDM.DocIdField, + createdAt: DynamoDM.CreatedAtField, + text: {type: 'string' }, + user: DynamoDM.DocId + }, + additionalProperties: true +}, index: { + findByUser: { + hashKey: 'user', + sortKey: 'createdAt' + } +})); + +// wait for the table to be ready (created if necessary, creation of index): +await table.ready(); + + +// create some documents (instances of models): +const aUser = new UserModel({emailAddress:"friend@example.com"}); +await aUser.save(); + +const aComment = new CommentModel({user: aUser.id, text: "My first comment."}); +await aComment.save(); + +// query for some documents: +const commentsForUser = await CommentModel.queryMany({user: aUser.id}); + +``` + +## Philosophy +DynamoDM is designed to make it simple to write simple apps that use DynamoDB, +preferring the single-table-design approach, where different model types are +mixed into a single DynamoDB table. + +Not all DynamoDB functions are available, nor will they be, but DynamoDM is +designed to be efficient, and make it easy to write apps that make the most of +DynamoDB's scalability, performance, and low cost. + +The simple API is inspired by [Mongoose](https://mongoosejs.com), but there are +many differences between MongoDB and DynamoDB, in particular when it comes to +querying documents: DynamDB's indexing and query capabilities are much more +limited, + + +## API +... + +### Sponsors +This project is supported by: + * [TraitorBird](https://traitorbird.com), simple canary tokens. + * [Coggle](https://coggle.it), simple collaborative mind maps. + diff --git a/test/index.js b/test/index.js new file mode 100644 index 0000000..b4f2dbc --- /dev/null +++ b/test/index.js @@ -0,0 +1,1716 @@ +const t = require('tap'); + +const clientOptions = { + endpoint: 'http://localhost:8000' +}; + +const DynamoDMConstructor = require('../'); +const DynamoDM = DynamoDMConstructor({clientOptions, logger:{level:'error'}}); + +async function arrayFromAsync(iter) { + const r = []; + for await (const x of iter) { + r.push(x); + } + return r; +} + +t.pass('import ok'); + +t.test('promiseAllWithCancellation', async t => { + const delayMsThenResolve = async (ms) => new Promise(resolve => setTimeout(() => resolve(`resolve value ${ms}`), ms)); + const delayMsThenReject = async (ms) => new Promise((ignored_resolve, reject) => setTimeout(() => reject(`reject value ${ms}`), ms)); + const promiseAllWithCancellation = DynamoDMConstructor.promiseAllWithCancellation; + + t.test('without cancellation should wait for all', async t => { + const results = await promiseAllWithCancellation([ + delayMsThenResolve(5), + delayMsThenResolve(10), + delayMsThenResolve(15), + ]); + const results2 = await Promise.all([ + delayMsThenResolve(5), + delayMsThenResolve(10), + delayMsThenResolve(15), + ]); + t.match(results, results2); + }); + + t.test('without cancellation should stop at first rejection', async t => { + let results1, results2, rejection1, rejection2; + try { + results1 = await promiseAllWithCancellation([ + delayMsThenResolve(5), + delayMsThenReject(10), + delayMsThenResolve(100), + ]); + } catch(e) { + rejection1 = e; + } + try{ + results2 = await Promise.all([ + delayMsThenResolve(5), + delayMsThenReject(10), + delayMsThenResolve(100), + ]); + } catch(e) { + rejection2 = e; + } + t.match(results1, results2, 'should not have results'); + t.match(rejection1, rejection2, 'should reject with "reject value 10"'); + }); + + t.test('cancellation by resolve should work', async t => { + let cancel, cancelled = new Promise((resolve, ignored_reject) => {cancel = resolve;}); + + const promises = [ + delayMsThenResolve(5), + delayMsThenResolve(10), + delayMsThenResolve(15), + ]; + + const pending = promiseAllWithCancellation(promises, cancelled); + await promises[0]; + cancel(); + await t.rejects(pending, new Error('Operation cancelled.'), 'should reject on cancellation after fulfillment of a promise'); + }); + + t.test('immediate cancellation by resolve should work', async t => { + let cancel, cancelled = new Promise((resolve, ignored_reject) => {cancel = resolve;}); + + const promises = [ + delayMsThenResolve(5), + delayMsThenResolve(10), + delayMsThenResolve(15), + ]; + + const pending = promiseAllWithCancellation(promises, cancelled); + cancel(new Error('foo')); + await t.rejects(pending, new Error('foo'), 'should reject on cancellation before fulfillment of any promises'); + }); + + t.test('cancelation after resolve should be harmless', async t => { + let cancel, cancelled = new Promise((resolve, ignored_reject) => {cancel = resolve;}); + + const promises = [ + delayMsThenResolve(5), + delayMsThenResolve(10), + delayMsThenResolve(15), + ]; + + const results = await promiseAllWithCancellation(promises, cancelled); + cancel(new Error('bar')); + t.match(results, ['resolve value 5', 'resolve value 10', 'resolve value 15']); + }); + + t.test('cancelation after reject should be harmless', async t => { + let cancel, cancelled = new Promise((resolve, ignored_reject) => {cancel = resolve;}); + + const promises = [ + delayMsThenResolve(5), + delayMsThenResolve(10), + delayMsThenReject(15), + ]; + + await t.rejects(promiseAllWithCancellation(promises, cancelled), 'reject value 15', 'should reject with value 15'); + cancel(new Error('bar')); + t.ok("shouldn't have thrown or caused unhandled rejection"); + }); + + t.test('invalid cancelation', async t => { + await t.rejects(promiseAllWithCancellation([], {then:123}), {message:'Cancellation must be thenable.'}, 'should reject invalid cancellation'); + }); + + await t.end(); +}); + +t.test('incorrect usage throws', async t => { + const DynamoDMConstructor = require('../../dynamodm'); + t.throws(() => { + DynamoDMConstructor.Table({name: 'test-table-1'}); + }, {message: "DynamoDM must be called as a function to get an instance of the API, e.g. const DynamoDM = require('dynamodm')(options);"}, 'DynamoDM.Table() throws'); + + t.throws(() => { + DynamoDMConstructor.Schema('emptySchema'); + }, {message: "DynamoDM must be called as a function to get an instance of the API, e.g. const DynamoDM = require('dynamodm')(options);"}, 'DynamoDM.Schema() throws'); +}); + +t.test('table initialisation', async t => { + await t.test('create without schemas', async t => { + const table = DynamoDM.Table({ name: 'test-table-1', clientOptions}); + await t.rejects(table.ready()); + }); + await t.test('create with schema', async t => { + const table = DynamoDM.Table({ name: 'test-table-2', clientOptions}); + table.model(DynamoDM.Schema('emptySchema')); + await table.ready(); + + await t.test('call ready multiple times', async () => { + await table.ready(); + }); + }); + + await t.test('with abstract logger', async t => { + const table = require('../../dynamodm')({logger: false}).Table({ name: 'test-table-2', clientOptions}); + table.model(DynamoDM.Schema('emptySchema')); + await table.ready(); + + await t.test('call ready multiple times', async () => { + await table.ready(); + }); + }); + + await t.test('asumme ready', async t => { + const table = DynamoDM.Table({ name: 'test-table-2'}, {clientOptions}); + table.model(DynamoDM.Schema('emptySchema')); + const r = table.assumeReady(); + t.equal(r, undefined, 'should return undefined (not be async)'); + t.throws(() => { + table.model(DynamoDM.Schema('emptySchema')); + }, 'should prevent adding further schemas'); + }); +}); + +t.test('basic schemas:', async t => { + const table = DynamoDM.Table({ name: 'test-table-schemas'}); + + await t.test('empty schema', async t => { + // models should have default .id, .type, .createdAt, .updatedAt properties + const EmptySchema = DynamoDM.Schema('emptySchema'); + t.hasStrict(EmptySchema, { name:'emptySchema', idFieldName:'id', typeFieldName:'type' }); + + const EmptyModel = table.model(EmptySchema); + const EmptyDoc = new EmptyModel(); + + t.hasOwnProps(EmptyDoc, ['id'], 'should have id'); + const asObj = await EmptyDoc.toObject(); + t.hasOwnProps(asObj, ['type', 'id'], 'should have id and type fields in toObject'); + t.equal(Object.keys(asObj).length, 2, 'should have no other fields in toObject'); + + t.end(); + }); + + await t.test('complex schema', async t => { + const ThingSchema = DynamoDM.Schema('namespace.thing', { + properties: { + id: DynamoDM.DocIdField, + aaaa: {type: 'string'}, + bbbb: {type: 'number'}, + cccc: {type: 'string'}, + blob: DynamoDM.Binary, + createdAt: DynamoDM.CreatedAtField, + updatedAt: DynamoDM.UpdatedAtField, + }, + required: ['id', 'aaaa', 'bbbb'], + additionalProperties: false + }, { + index: { + // index called 'findByCreated', .type hash key, '.createdAt' sort key + findByCreated: { + hashKey: 'type', + sortKey: 'createdAt' + } + } + }); + + const DefaultValueTestSchema = DynamoDM.Schema('namespace.defaultvalue', { + properties: { + a: {type: 'string', default:'foo'}, + b: {type: 'number', default: 123}, + c: {type: 'number', default: 456}, + d: {type: 'array', items: {type:'number'}, default:[1]} + } + }); + + const ThingModel = table.model(ThingSchema); + const DefaultValueTestModel = table.model(DefaultValueTestSchema); + + await table.ready({waitForIndexes: true}); + await table.ready(); + + t.test('create a valid doc', async t => { + const props = { + aaaa: 'a', + bbbb: 123, + blob: Buffer.from('hello') + }; + const ValidThingDoc = new ThingModel(props); + t.hasStrict(ValidThingDoc, props); + t.hasOwnProps(ValidThingDoc, ['id', 'type']); + // createdAt and updatedAt are only set when saved + t.notMatch(ValidThingDoc, ['createdAt', 'updatedAt']); + await ValidThingDoc.save(); + t.hasOwnProps(ValidThingDoc, ['createdAt', 'updatedAt']); + t.end(); + }); + + t.test('invalid docs throw', async t => { + t.throws(() => {new ThingModel({aaaa: 123});}); + t.throws(() => {new ThingModel({blob: 123});}); + t.end(); + }); + + t.test('default values', async t => { + const defaultTestDoc = new DefaultValueTestModel({c:3}); + t.hasStrict(defaultTestDoc, {a:'foo', b:123, c:3, d:[1]}); + + const testDoc2 = new DefaultValueTestModel({c:4, d:[]}); + t.hasStrict(testDoc2, {a:'foo', b:123, c:4, d:[]}); + t.end(); + }); + + t.test('setting default values on load', async t => { + const doc = new ThingModel({ aaaa: 'a', bbbb: 123, blob: Buffer.from('hello') }); + await doc.save(); + const loaded = await DefaultValueTestModel.getById(doc.id); + t.hasStrict(loaded, {a:'foo', b:123, c:456, d:[1]}); + t.end(); + }); + + t.test('toObject', async t => { + const defaultTestDoc = new DefaultValueTestModel({c:3}); + const asObj = await defaultTestDoc.toObject(); + t.hasStrict(asObj, { + a:'foo', b:123, c:3, d:[1] + }, 'should always have all schema fields'); + + defaultTestDoc.z = 4; + t.hasStrict(await defaultTestDoc.toObject(), { + a:'foo', b:123, c:3, d:[1], z:4 + }, 'should have additional field'); + }); + + t.test('undefined property should be treated as non-existent', async t => { + const props = { + aaaa: 'a', + bbbb: 123, + cccc: undefined + }; + let doc = new ThingModel(props); + t.notHas(doc, {cccc:1}); + t.equal(doc.cccc, undefined); + t.hasStrict(doc, props); + + await table.ready({waitForIndexes: true}); + + await doc.save(); + t.notHas(doc, {cccc:1}); + t.equal(doc.cccc, undefined); + t.hasStrict(doc, props); + + doc = await ThingModel.getById(doc.id); + t.notHas(doc, {cccc:1}); + t.equal(doc.cccc, undefined); + t.hasStrict(doc, props); + + t.end(); + }); + + t.end(); + }); + + t.test('arrays', async t => { + const arraysTable = DynamoDM.Table({ name: 'test-table-arrays'}); + const ArrayOfStringsSchema = DynamoDM.Schema('namespace.array1', { + properties: { + anArray: { + type: 'array', + items: { + type: 'string' + } + } + }, + required: ['anArray'], + additionalProperties: false + }); + const ArrayOfMixedTypesSchema = DynamoDM.Schema('namespace.array2', { + properties: { + anArray: { + type: 'array', + } + }, + required: ['anArray'], + additionalProperties: false + }); + const ArrayOfTimestampsSchema = DynamoDM.Schema('namespace.array3', { + properties: { + anArray: { + type: 'array', + items: DynamoDM.Timestamp + } + }, + required: ['anArray'], + additionalProperties: false + }); + + const ArrayOfStrings = arraysTable.model(ArrayOfStringsSchema); + const ArrayOfMixedTypes = arraysTable.model(ArrayOfMixedTypesSchema); + const ArrayOfTimestamps = arraysTable.model(ArrayOfTimestampsSchema); + + await arraysTable.ready(); + await arraysTable.ready({waitForIndexes:true}); + + t.test('create a valid doc', async t => { + const props1 = {anArray:['a', 'b']}; + const props2 = {anArray:['a', 1, {b:3}]}; + const props3 = {anArray:[new Date(), new Date()]}; + const ValidArrayOfStringsDoc = new ArrayOfStrings(props1); + const ValidArrayOfMixedDoc = new ArrayOfMixedTypes(props2); + const ValidArrayOfTimestampsDoc = new ArrayOfTimestamps(props3); + t.hasStrict(ValidArrayOfStringsDoc, props1); + t.hasStrict(ValidArrayOfMixedDoc, props2); + t.hasStrict(ValidArrayOfTimestampsDoc, props3); + await ValidArrayOfStringsDoc.save(); + await ValidArrayOfMixedDoc.save(); + await ValidArrayOfTimestampsDoc.save(); + t.end(); + }); + + t.test('invalid docs throw', async t => { + t.throws(() => {new ArrayOfStrings({anArray: [1]});}, + {message:'Document does not match schema for namespace.array1: /anArray/0 must be string.'}, 'number as string'); + t.throws(() => {new ArrayOfStrings({anArray: [{a:1}]});}, + {message:'Document does not match schema for namespace.array1: /anArray/0 must be string.'}, 'object as string'); + t.throws(() => {new ArrayOfStrings({anArray: [Buffer.from('test', 'ascii')]});}, + {message:'Document does not match schema for namespace.array1: /anArray/0 must be string.'}, 'buffer as string'); + t.throws(() => {new ArrayOfMixedTypes({anArray: {1:'a'}});}, + {message:'Document does not match schema for namespace.array2: /anArray must be array.'}, 'object as array'); + t.throws(() => {new ArrayOfMixedTypes({anArray: 2});}, + {message:'Document does not match schema for namespace.array2: /anArray must be array.'}, 'number as array'); + t.throws(() => {new ArrayOfMixedTypes({anArray: new Date()});}, + {message:'Document does not match schema for namespace.array2: /anArray must be array.'}, 'date as array'); + t.throws(() => {new ArrayOfMixedTypes({anArray: Buffer.from('test', 'ascii')});}, + {message:'Document does not match schema for namespace.array2: /anArray must be array.'}, 'buffer as array'); + t.throws(() => {new ArrayOfTimestamps({anArray: [new Date(), 'a']});}, + {message:'Document does not match schema for namespace.array3: /anArray/1 must be a Date.'}, 'string as timestamp'); + t.throws(() => {new ArrayOfTimestamps({anArray: [1]});}, + {message:'Document does not match schema for namespace.array3: /anArray/0 must be a Date.'}, 'number as timestamp'); + t.end(); + }); + + t.end(); + }); + + t.test('.methods', async t => { + const methodsTable = DynamoDM.Table({ name: 'test-table-methods'}); + + const FooSchema = DynamoDM.Schema('namespace.foo'); + FooSchema.methods.getMyId = function getMyId(){ + return this.id; + }; + + const ThingSchema = DynamoDM.Schema('namespace.thing', { + properties: { + id: DynamoDM.DocIdField, + aaaa: {type: 'string'}, + bbbb: {type: 'number'}, + blob: DynamoDM.Binary, + createdAt: DynamoDM.CreatedAtField, + updatedAt: DynamoDM.UpdatedAtField, + }, + required: ['id', 'aaaa', 'bbbb'], + additionalProperties: false + }, { + index: { + // index called 'findByCreated', .type hash key, '.createdAt' sort key + findByCreated: { + hashKey: 'type', + sortKey: 'createdAt' + } + } + }); + ThingSchema.methods.incrementThenSave = async function incSave(){ + this.bbbb += 1; + return await this.save(); + }; + const InvalidMethodSchema = DynamoDM.Schema('namespace.invalidMethod'); + InvalidMethodSchema.methods.constructor = function notAllowed(){ }; + + const FooModel = methodsTable.model(FooSchema); + const ThingModel = methodsTable.model(ThingSchema); + + t.test('does not allow invalid method names', async t => { + t.throws(() => { + methodsTable.model(InvalidMethodSchema); + }, {message:"The name 'constructor' is reserved and cannot be used for a method."}, 'should not allow .constructor() method'); + }); + + const foo = new FooModel(); + t.equal(foo.getMyId, FooSchema.methods.getMyId, 'creates with methods'); + t.equal(foo.getMyId(), foo.id, 'methods are callable'); + + const thing = new ThingModel({aaaa:'a', bbbb:1}); + t.equal(thing.incrementThenSave, ThingSchema.methods.incrementThenSave, 'creates with async methods'); + t.resolves(thing.incrementThenSave(), 'async methods work'); + }); + + t.test('.statics', async t => { + const staticsTable = DynamoDM.Table({ name: 'test-table-2'}); + + const FooSchema = DynamoDM.Schema('namespace.foo', {b: {type: 'number', default: 0}}); + FooSchema.statics.testStatic = function getMyId(){ + return 4; + }; + FooSchema.statics.testAsyncStatic = async function getMyId(){ + return 4; + }; + + const FooModel = staticsTable.model(FooSchema); + + t.equal(FooModel.testStatic, FooSchema.statics.testStatic, 'creates with statics'); + t.equal(FooModel.testStatic(), 4, 'statics are callable'); + t.resolves(FooModel.testAsyncStatic(), 'async statics work'); + }); +}); + +t.test('virtuals:', async t => { + t.test('string aliases', async t => { + const table = DynamoDM.Table({ name: 'test-table-2'}); + const ASchema = DynamoDM.Schema('virtualsA', { + properties: { + foo: {type: 'number', default: 3} + }, + additionalProperties: false + }); + ASchema.virtuals.bar = 'foo'; + + const AModel = table.model(ASchema); + + const aDoc = new AModel(); + const bDoc = new AModel(); + t.equal(aDoc.bar, 3, 'alias should be initialised on construction'); + aDoc.foo = 4; + bDoc.foo = 5; + t.equal(aDoc.bar, 4, 'alias should be set on assignment, and be unique amongst instances'); + t.equal(bDoc.bar, 5, 'alias should be set on assignment'); + await aDoc.save(); + + const aDocAsObj = await aDoc.toObject(); + t.equal(aDocAsObj.bar, 4, 'alias should be included in toObject()'); + + const loaded = await AModel.getById(aDoc.id); + t.equal(loaded.bar, 4, 'alias should be initialised on load'); + + loaded.bar = 7; + t.equal(loaded.foo, 7, 'alias assignment should work'); + + const asObjWithoutVirtuals = await loaded.toObject({virtuals: false}); + t.equal(asObjWithoutVirtuals.bar, undefined, 'should not be included with {virtuals: false}'); + }); + + t.test('getters', async t => { + const table = DynamoDM.Table({ name: 'test-table-2'}); + const ASchema = DynamoDM.Schema('testGetters', { + additionalProperties: false + }); + ASchema.virtuals.nonPrefixedId = { + get: function() { + return this.id.split('.')[1]; + } + }; + + const AModel = table.model(ASchema); + + const aDoc = new AModel(); + const id = aDoc.id.split('.')[1]; + t.equal(aDoc.nonPrefixedId, id, 'getter should work on construction'); + t.throws(() => { aDoc.nonPrefixedId = 'something'; }, 'setting should throw'); + await aDoc.save(); + + const aDocAsObj = await aDoc.toObject(); + t.equal(aDocAsObj.nonPrefixedId, id, 'getter should be included in toObject()'); + + const loaded = await AModel.getById(aDoc.id); + t.equal(loaded.nonPrefixedId, id, 'getter should be initialised on load'); + + const asObjWithoutVirtuals = await loaded.toObject({virtuals: false}); + t.equal(asObjWithoutVirtuals.nonPrefixedId, undefined, 'should not be included with {virtuals: false}'); + }); + + t.test('invalid descriptors', async t => { + const table = DynamoDM.Table({ name: 'test-table-2'}); + const ASchema = DynamoDM.Schema('testErrors', { + properties: { + foo: {type: 'number', default: 3} + }, + additionalProperties: false + }); + ASchema.virtuals.bar = 'unknown'; + + t.throws(() => { + table.model(ASchema); + }, {message: 'Virtual property "bar" is an alias for an unknown property "unknown".'}, 'throw on invalid alias'); + + + ASchema.virtuals = { + bar: { + notValid: 1 + } + }; + t.throws(() => { + table.model(ASchema); + }, {message: 'Virtual property "bar" invalid descriptor key "notValid" is not one of \'configurable\', \'enumerable\', \'value\', \'writable\', \'get\' or \'set\'.'}, 'throw on invalid descriptor'); + + ASchema.virtuals = { + bar: 123 + }; + t.throws(() => { + table.model(ASchema); + }, {message: 'Virtual property "bar" must be a string alias, or a data descriptor or accessor descriptor.'}, 'throw on invalid descriptor type'); + + }); + + t.test('enumerable', async t => { + const table = DynamoDM.Table({ name: 'test-table-2'}); + const ASchema = DynamoDM.Schema('testEnumerable', { + properties: { foo: { type: 'number'} }, + additionalProperties: false + }); + ASchema.virtuals.someEnumerable = { + value: 4, + enumerable: true + }; + + const AModel = table.model(ASchema); + + const aDoc = new AModel(); + await aDoc.save(); + t.equal(aDoc.someEnumerable, 4, 'enumerable virtual should work'); + // only 'for ... in' actually iterates over inherited enumerable properties: + let found = false; + for (const prop in aDoc) { + if (prop === 'someEnumerable') found = true; + } + t.equal(found, true, 'enumerable virtual should be enumerable'); + t.equal(Object.keys(aDoc).indexOf('someEnumerable'), -1, 'enumerable virtual is not an own-property, so should not be in Object.keys()'); + + const aDocAsObj = await aDoc.toObject(); + t.equal(aDocAsObj.someEnumerable, 4, 'should be included in toObject()'); + + const loaded = await AModel.getById(aDoc.id); + t.equal(loaded.someEnumerable, 4, 'should be initialised on load'); + + const asObjWithoutVirtuals = await loaded.toObject({virtuals: false}); + t.equal(asObjWithoutVirtuals.someEnumerable, undefined, 'should not be included with {virtuals: false}'); + }); +}); + +t.test('converters:', async t => { + t.test('sync field creation and deletion', async t => { + const table = DynamoDM.Table({ name: 'test-table-2'}); + const ASchema = DynamoDM.Schema('testConverters', { + properties: { + foo: {type: 'number', default: 3}, + bar: {type: 'number', default: 4} + }, + additionalProperties: false + }); + let AModel; + const optionAValue = {}; + ASchema.converters.push(function(value, options){ + // eslint-disable-next-line + t.equal(this.constructor, AModel, 'this should be a model instance'); + // eslint-disable-next-line + t.equal(this.constructor.table, table, 'this.constructor should provide access to model statics'); + t.equal(options.a, optionAValue, 'options values should be preserved'); + delete value.bar; + return value; + }); + ASchema.converters.push(function(value){ + value.newField = 3; + return value; + }); + ASchema.converters.push(function(value){ + value.newField2 = value.newField + 1; + return value; + }); + + AModel = table.model(ASchema); + + const aDoc = new AModel(); + + const aDocAsObj = await aDoc.toObject({a:optionAValue}); + t.equal(aDocAsObj.foo, 3, 'non deleted field should remain'); + t.equal(aDocAsObj.bar, undefined, 'deleted field should be deleted'); + t.equal(aDocAsObj.newField2, 4, 'converters should be executed in series'); + t.equal(aDocAsObj.newField, 3, 'converter should work'); + }); + + t.test('async field creation', async t => { + const table = DynamoDM.Table({ name: 'test-table-2'}); + const ASchema = DynamoDM.Schema('testConverters', { + additionalProperties: false + }); + ASchema.converters.push(async function(){ + await new Promise(resolve => setTimeout(resolve, 10)); + return { + newField: 3 + }; + }); + ASchema.converters.push(async function(value){ + await new Promise(resolve => setTimeout(resolve, 10)); + value.newField2 = value.newField + 1; + return value; + }); + ASchema.converters.push(async function(value, options){ + await new Promise(resolve => setTimeout(resolve, 10)); + value.newField3 = options.newField3Value; + return value; + }); + + const AModel = table.model(ASchema); + + const aDoc = new AModel(); + + const aDocAsObj = await aDoc.toObject({newField3Value: 7}); + t.equal(aDocAsObj.newField, 3, 'async converter should work'); + t.equal(aDocAsObj.newField2, 4, 'async converters should be executed in series'); + t.equal(aDocAsObj.newField3, 7, 'async converters should be executed in series'); + }); + + t.test('errors', async t => { + const table = DynamoDM.Table({ name: 'test-table-2'}); + const ASchema = DynamoDM.Schema('testGetters', { + additionalProperties: false + }); + ASchema.converters.push('something'); + + t.throws(() => { + table.model(ASchema); + }, {message:'Converters must be functions or async functions: typeof converters[0] is string.'}, 'pushing a non-function type should throw'); + }); +}); + + + +t.test('custom field names', async t => { + const table = DynamoDM.Table({ name: 'test-table-custom-names'}); + + // models should have default .id, .type, .createdAt, .updatedAt properties + const Schema = DynamoDM.Schema('schema1', { + properties: { + myId: DynamoDM.DocIdField, + myType: DynamoDM.TypeField, + myCreatedAt: DynamoDM.CreatedAtField, + myUpdatedAt: DynamoDM.UpdatedAtField + } + }); + t.hasStrict(Schema, { name:'schema1', idFieldName:'myId', typeFieldName:'myType', createdAtFieldName:'myCreatedAt', updatedAtFieldName:'myUpdatedAt' }); + + const Model = table.model(Schema); + + const doc = new Model(); + await doc.save(); + + t.hasOwnProps(doc, ['myId', 'myType', 'myCreatedAt', 'myUpdatedAt']); +}); + + +t.test('table consistency:', async t => { + await t.test('throws on inconsistent id field names', async t => { + const table = DynamoDM.Table({ name: 'test-table-errors'}); + table.model(DynamoDM.Schema('schema1')); + table.model(DynamoDM.Schema('schema2')); + table.model(DynamoDM.Schema('schema3', { + properties:{ + idFieldA: DynamoDM.DocIdField + } + })); + t.rejects(table.ready()); + t.throws(() => { table.assumeReady(); }); + }); + + await t.test('throws on inconsistent type field names', async t => { + const table = DynamoDM.Table({ name: 'test-table-errors'}); + table.model(DynamoDM.Schema('schema1')); + table.model(DynamoDM.Schema('schema2', { + properties:{ + typeFieldA: DynamoDM.TypeField + } + })); + table.model(DynamoDM.Schema('schema3', { + properties:{ + typeFieldB: DynamoDM.TypeField + } + })); + t.rejects(table.ready()); + }); + + await t.test('rejects on ready for schema name collisions', async t => { + const table = DynamoDM.Table({ name: 'test-table-errors'}); + table.model(DynamoDM.Schema('schema1')); + table.model(DynamoDM.Schema('schema1')); + t.rejects(table.ready()); + }); + + await t.test('rejects on ready after destroyConnection', async t => { + const table = DynamoDM.Table({ name: 'test-table-errors'}); + table.model(DynamoDM.Schema('schema1')); + await table.ready(); + table.destroyConnection(); + t.rejects(table.ready(), {message: 'Connection has been destroyed.'}, 'rejects on ready()'); + }); + + await t.test('incorrect type index', async t => { + const table1 = DynamoDM.Table({ name: 'incorrect-type-index'}); + const table2 = DynamoDM.Table({ name: 'incorrect-type-index'}); + table1.model(DynamoDM.Schema('schema1', { + properties: { + typefield_B: DynamoDM.TypeField + } + })); + table2.model(DynamoDM.Schema('schema1', { + properties: { + typefield_A: DynamoDM.TypeField + } + })); + + t.teardown(async () => { + await table1.deleteTable(); + table1.destroyConnection(); + table2.destroyConnection(); + }); + + await table1.ready(); + // FIXME: currently this will log a warning, which we cannot easily check for + await table2.ready(); + }); + + await t.test('returns existing model for existing schema', async t => { + const table = DynamoDM.Table({ name: 'test-table-errors'}); + const schema = DynamoDM.Schema('schema1'); + const m1 = table.model(schema); + const m2 = table.model(schema); + t.equal(m1, m2); + await table.ready(); + const m3 = table.model(schema); + t.equal(m1, m3); + }); + + await t.test('throws on adding schemas after ready', async t => { + const table = DynamoDM.Table({ name: 'test-table-errors'}); + const schema1 = DynamoDM.Schema('schema1'); + const schema2 = DynamoDM.Schema('schema2'); + table.model(schema1); + await table.ready(); + t.throws( () => { table.model(schema2); }); + }); + + await t.test('throws on invalid table name', async t => { + t.throws(() => { + DynamoDM.Table({ name: '1'}); + }, /Invalid table name.*/); + }); + + await t.test('throws on invalid index name', async t => { + const table = DynamoDM.Table({ name: 'test-table-errors'}); + t.throws(() => { + table.model(DynamoDM.Schema('schema2', { + properties:{ a: {type:'string'} } + }, { + index: { + // index names need to be at least three chars for some reason, so this is expected to be invalid + a: 1 + } + })); + }, /Invalid index name.*/); + }); +}); + +t.test('crud:', async t => { + const table = DynamoDM.Table({ name: 'test-table-crud'}); + const ThingSchema = DynamoDM.Schema('namespace.thing', { + properties: { + id: DynamoDM.DocIdField, + aaaa: {type: 'string'}, + bbbb: {type: 'number'}, + cccc: {type: 'string'}, + blob: DynamoDM.Binary, + createdAt: DynamoDM.CreatedAtField, + updatedAt: DynamoDM.UpdatedAtField, + }, + required: ['id', 'aaaa', 'bbbb'], + additionalProperties: false + }); + const Thing = table.model(ThingSchema); + + await table.ready(); + + let x, y; + await t.test('create', async t => { + x = new Thing({aaaa: 'a', bbbb:1, blob: Buffer.from('hello crud'), }); + await x.save(); + + y = await Thing.getById(x.id); + t.strictSame(y, x); + + t.end(); + }); + + await t.test('update', async t => { + x.bbbb = 2; + await x.save(); + + y = await Thing.getById(x.id); + t.strictSame(y, x); + + t.end(); + }); + + await t.test('remove', async t => { + const oldId = x.id; + await x.remove(); + + t.equal(await Thing.getById(oldId), null); + + t.end(); + }); + + await t.test('creating with duplicate ids should fail', async t => { + x = new Thing({aaaa: 'a', bbbb:1, blob: Buffer.from('hello crud'), id: 'duplicate'}); + y = new Thing({aaaa: 'b', bbbb:2, blob: Buffer.from('hello crud'), id: 'duplicate'}); + await x.save(); + t.rejects(y.save(), {}, 'creating duplicate'); + + t.end(); + }); + + await t.test('deleting buffer fields', async t => { + t.test('delete buffer and re-save', async t => { + x = new Thing({aaaa: 'a', bbbb:1, blob: Buffer.from('hello crud'), id: 'hadblob1'}); + await x.save(); + + delete x.blob; + await x.save(); + + y = await Thing.getById('hadblob1'); + t.equal(y.blob, undefined, 'blob should be gone'); + + t.end(); + }); + + t.test('delete buffer by setting undefined', async t => { + x = new Thing({aaaa: 'a', bbbb:1, blob: Buffer.from('hello crud'), id: 'hadblob2'}); + await x.save(); + + x.blob = undefined; + await x.save(); + + y = await Thing.getById('hadblob2'); + t.equal(y.blob, undefined, 'blob should be gone'); + + t.end(); + }); + + t.test('delete buffer by saving over', async t => { + x = new Thing({aaaa: 'a', bbbb:1, blob: Buffer.from('hello crud'), id: 'hadblob3'}); + await x.save(); + + y = await Thing.getById('hadblob3'); + delete y.blob; + await y.save(); + + t.equal(y.blob, undefined, 'blob should be gone'); + + y = await Thing.getById('hadblob3'); + t.equal(y.blob, undefined, 'blob should still be gone after load'); + + t.end(); + }); + }); + + await t.test('deleting string fields', async t => { + t.test('delete string and re-save', async t => { + x = new Thing({aaaa: 'a', bbbb:1, cccc: 'hello', id: 'hadstring1'}); + await x.save(); + + delete x.cccc; + await x.save(); + + y = await Thing.getById('hadstring1'); + t.equal(y.cccc, undefined, 'cccc should be gone'); + + t.end(); + }); + + t.test('delete string by setting undefined', async t => { + x = new Thing({aaaa: 'a', bbbb:1, cccc: 'hello', id: 'hadstring2'}); + await x.save(); + + x.cccc = undefined; + await x.save(); + + y = await Thing.getById('hadstring2'); + t.equal(y.cccc, undefined, 'cccc should be gone'); + + t.end(); + }); + + t.test('delete string by saving over', async t => { + x = new Thing({aaaa: 'a', bbbb:1, cccc: 'hello', id: 'hadstring3'}); + await x.save(); + + y = await Thing.getById('hadstring3'); + delete y.cccc; + await y.save(); + + t.equal(y.cccc, undefined, 'cccc should be gone'); + + y = await Thing.getById('hadstring3'); + t.equal(y.cccc, undefined, 'cccc should still be gone after load'); + + t.end(); + }); + }); + + t.teardown(async () => { + await table.deleteTable(); + table.destroyConnection(); + }); + + t.end(); +}); + +t.test('schema errors', async t => { + const table = DynamoDM.Table({ name: 'test-table-schemas'}); + + const AStringSchema = DynamoDM.Schema('namespace.thing', { properties: { a: {type: 'string'}, } }); + const ARequiredStringSchema = DynamoDM.Schema('namespace.thing', { properties: { b: {type: 'string'}, }, required:['b'] }); + const ABinarySchema = DynamoDM.Schema('namespace.thing', { properties: { a: DynamoDM.Binary, } }); + const ATimestampSchema = DynamoDM.Schema('namespace.thing', { properties: { a: DynamoDM.Timestamp, } }); + const ARequiredTimestampSchema = DynamoDM.Schema('namespace.thing', { properties: { b: DynamoDM.Timestamp, }, required:['b'] }); + const AnUnknownSchema = DynamoDM.Schema('namespace.thing', { properties: { a: {'extendedType':'foo'} } }); + const ANestedStringSchema = DynamoDM.Schema('namespace.thing2', { properties: { nested: { type:'object', properties: {a: {type: 'string'}, } } } }); + const ANestedBinarySchema = DynamoDM.Schema('namespace.thing2', { properties: { nested: { type:'object', properties: {a: DynamoDM.Binary, } } } }); + const ANestedArrayStringSchema = DynamoDM.Schema('namespace.thing3', { properties: { nestedArray: { type:'array', items: {type: 'string'} } } }); + const ANestedArrayUnknownSchema = DynamoDM.Schema('namespace.thing3', { properties: { nestedArray: { type:'array', items: {'extendedType':'foo'} } } }); + const ANestedArrayTimestampSchema = DynamoDM.Schema('namespace.thing3', { properties: { nestedArray: { type:'array', items: DynamoDM.Timestamp } } }); + const AString = table.model(AStringSchema); + const ARequiredString = table.model(ARequiredStringSchema); + const ABinary = table.model(ABinarySchema); + const ATimestamp = table.model(ATimestampSchema); + const ARequiredTimestamp = table.model(ARequiredTimestampSchema); + const AnUnknown = table.model(AnUnknownSchema); + const ANestedString = table.model(ANestedStringSchema); + const ANestedBinary = table.model(ANestedBinarySchema); + const ANestedArrayString = table.model(ANestedArrayStringSchema); + const ANestedArrayUnknown = table.model(ANestedArrayUnknownSchema); + const ANestedArrayTimestamp = table.model(ANestedArrayTimestampSchema); + + await t.test('invalid schema type', async t => { + t.throws(() => { table.model({type:'object', properties:{a:{type:'string'}}} ); }, {message: 'The model schema must be a valid DynamoDM.Schema().'}, 'plain object schema'); + t.throws(() => { DynamoDM.Schema('invalid', 123); }, {message: 'Invalid schema: must be an object or undefined.'}, 'invalid Schema() construction'); + }); + + await table.ready({allowAliasedSchemas: true}); + + await t.test('invalid schemas', async t => { + t.throws(() => { DynamoDM.Schema({ properties: { a: {type: 'string'}, } }); }, {message: 'Invalid name: must be a string.'}, 'unnamed schema'); + t.throws(() => { DynamoDM.Schema('somemodel', { type: 'string' }); }, {message: 'Schema type must be object (or can be omitted).'}, 'unnamed schema'); + t.throws(() => { DynamoDM.Schema('somemodel', { properties: { id: DynamoDM.DocIdField, _id: DynamoDM.DocIdField } }); }, {message: 'Duplicate id field.'}, 'duplicate id field'); + }); + + await t.test('instantiating invalid types', async t => { + t.throws(() => {new AString({a: 1 });}, {message: 'Document does not match schema for namespace.thing: /a must be string.'}, 'number as string'); + t.throws(() => {new ABinary({a: '' });}, {message: 'Document does not match schema for namespace.thing: /a must be a Buffer.'}, 'string as binary'); + t.throws(() => {new ATimestamp({a: '' });}, {message: 'Document does not match schema for namespace.thing: /a must be a Date.'}, 'string as timestamp'); + t.throws(() => {new AnUnknown({a: '' });}, {message: 'Document does not match schema for namespace.thing: /a is an unknown extended type.'}, 'string as invalid schema'); + }); + + await t.test('saving invalid types', async t => { + let x = new AString({a: '' }); + x.a = 1; + t.rejects(x.save(), {message: 'Document does not match schema for namespace.thing: /a must be string.'}, 'save number as string'); + + x = new ABinary({a: Buffer.from('hello') }); + x.a = ''; + t.rejects(x.save(), {message: 'Document does not match schema for namespace.thing: /a must be a Buffer.'}, 'save string as binary'); + + x = new ATimestamp({a: new Date() }); + x.a = ''; + t.rejects(x.save(), {message: 'Document does not match schema for namespace.thing: /a must be a Date.'}, 'save string as timestamp'); + + x = new AnUnknown(); + x.a = ''; + t.rejects(x.save(), {message: 'Document does not match schema for namespace.thing: /a is an unknown extended type'}, 'save string as unknown'); + }); + + await t.test('loading invalid types', async t => { + const x = new AString({a: 'a' }); + await x.save(); + + t.rejects(ABinary.getById(x.id), {message: 'Expected marshalled type of Buffer property a to be a Uint8Array (got string).'}, 'string as Buffer'); + t.rejects(ATimestamp.getById(x.id), {message: 'Expected marshalled type of Date property a to be a number (got string).'}, 'string as Date'); + t.rejects(AnUnknown.getById(x.id), {message: 'Document does not match schema for namespace.thing: /a is an unknown extended type.'}, 'string as unknown'); + }); + + await t.test('loading invalid nested types', async t => { + const x = new ANestedString({ nested: { a: 'a' }}); + await x.save(); + + t.rejects(ANestedBinary.getById(x.id), {message: 'Expected marshalled type of Buffer property a to be a Uint8Array (got string).'}, 'string as Buffer'); + }); + + await t.test('loading invalid array nested types', async t => { + const x = new ANestedArrayString({ nestedArray: ['a'] }); + await x.save(); + t.rejects(ANestedArrayTimestamp.getById(x.id), {message: 'Document does not match schema for namespace.thing3: /nestedArray/0 Expected marshalled type of Date property 0 to be a number (got string).'}, 'string as Timestamp'); + t.rejects(ANestedArrayUnknown.getById(x.id), {message: 'Document does not match schema for namespace.thing3: /nestedArray/0 is an unknown extended type.'}, 'string as unknown extended type'); + }); + + await t.test('saving missing required fields', async t => { + let x = new ARequiredString({b:''}); + x.b = undefined; + t.rejects(x.save(), /^Document does not match schema for namespace.thing: {2}must have required property 'b'/, 'missing simple type'); + x = new ARequiredTimestamp({b:new Date()}); + x.b = undefined; + t.rejects(x.save(), /^Document does not match schema for namespace.thing: {2}must have required property 'b'/, 'missing marshalled type'); + }); + + await t.test('loading missing required fields', async t => { + const x = new AString({a: 'a' }); + await x.save(); + + t.rejects(ARequiredString.getById(x.id), /^Document does not match schema for namespace.thing: {2}must have required property 'b'/, 'missing simple type'); + t.rejects(ARequiredTimestamp.getById(x.id), /^Document does not match schema for namespace.thing: {2}must have required property 'b'/, 'missing marshalled type'); + }); + + await t.test('invalid index specifiction', async t => { + t.throws(() => { + DynamoDM.Schema('namespace.shouldthrow', { + properties: { aaa: {type: 'string'}, bbb: {type: 'string'}, boolField: {type: 'boolean'} } + }, { + index: { + type: { + hashKey: 'aaa' + } + } + }); + }, {message: 'Invalid index name "type": this name is reserved for the built-in type index.'} , 'should throw creating an index called type'); + + t.throws(() => { + DynamoDM.Schema('namespace.shouldthrow', { + properties: { aaa: {type: 'string'}, bbb: {type: 'string'}, boolField: {type: 'boolean'} } + }, { + index: { + aaa: false + } + }); + }, {message: 'Invalid index specification ${indexSpec}: must be 1,true, or {hashKey:"", sortKey?:""}.'} , 'should throw with key:false'); + + t.throws(() => { + DynamoDM.Schema('namespace.shouldthrow', { + properties: { aaa: {type: 'string'}, bbb: {type: 'string'}, boolField: {type: 'boolean'} } + }, { + index: { + ccc: 1 + } + }); + }, {message: 'The schema must define the type of property .ccc used by index "ccc".'} , 'should throw referencing an unknown field'); + + + t.throws(() => { + DynamoDM.Schema('namespace.shouldthrow', { + properties: { aaa: {type: 'string'}, bbb: {type: 'string'}, boolField: {type: 'boolean'} } + }, { + index: { + boolField: 1 + } + }); + }, {message: 'The schema type of property .boolField, "{"type":"boolean"}" used by index "boolField" is not indexable.'} , 'should throw on a non-indexable field type'); + }); + + t.teardown(async () => { + await table.deleteTable(); + table.destroyConnection(); + }); +}); + +t.test('queries:', async t => { + const table = DynamoDM.Table({ name: 'test-table-queries'}); + const FooSchema = DynamoDM.Schema('namespace.foo', { + properties: { + id: DynamoDM.DocIdField, + fooVal: {type: 'number'}, + blob: DynamoDM.Binary, + padding: DynamoDM.Binary + } + }); + const BarSchema = DynamoDM.Schema('ambiguous.bar', { + properties: { + id: DynamoDM.DocIdField, + barVal: {type: 'number'}, + blob: DynamoDM.Binary + }, + required:['barVal'] + }, { + index: { + barValRange: { + hashKey: 'type', + sortKey: 'barVal' + } + } + }); + const AmbiguousSchema = DynamoDM.Schema('ambiguous', { + properties: { + id: DynamoDM.DocIdField, + } + }); + const IndexedStringSchema = DynamoDM.Schema('namespace.indexedString', { + properties: { + someString: {type: 'string'}, + someOtherString: {type: 'string'}, + someN: {type: 'number'} + } + }, { + index: { + someString: 1, + someOtherString: 1 + } + }); + const IndexedTsSchema = DynamoDM.Schema('namespace.indexedTs', { + properties: { + someTs: DynamoDM.Timestamp, + someN: {type: 'number'} + } + }, { + index: { + someTs: 1 + } + }); + const IncompatibleStringSchema = DynamoDM.Schema('namespace.incompatibleS', { + properties: { + someString: {type: 'number'}, + } + }, { + index: { + someString: 1 + } + }); + const IncompatibleString2Schema = DynamoDM.Schema('namespace.incompatibleS', { + properties: { + someString: {type: 'number'}, + foo: {type: 'string'} + } + }, { + index: { + someString: { + hashKey: 'foo' + } + } + }); + const CompatibleExtraStringSchema = DynamoDM.Schema('namespace.otherString', { + properties: { + otherString: {type: 'string'}, + num: {type: 'number'} + } + }, { + index: { + otherString: { + hashKey: 'otherString', + sortKey: 'num' + } + } + }); + const IndexedNumberAndBinarySchema = DynamoDM.Schema('namespace.indexedNB', { + properties: { + num: {type: 'number'}, + blob: DynamoDM.Binary, + } + }, { + index: { + num: 1, + myBinaryIndex: { + hashKey: 'blob', + sortKey: 'num' + }, + myNumIndex: { + hashKey: 'num', + sortKey: 'blob' + } + } + }); + const Foo = table.model(FooSchema); + const Bar = table.model(BarSchema); + const Ambiguous = table.model(AmbiguousSchema); + const IndexedString = table.model(IndexedStringSchema); + const IndexedTs = table.model(IndexedTsSchema); + const IndexedNumberAndBinary = table.model(IndexedNumberAndBinarySchema); + + // this should be creating indexes + await table.ready(); + + const all_foos = []; + for (let i = 0; i < 50; i++ ) { + // padd the Foo items out to 350KBk each, so that we can test bumping up against dynamoDB's 16MB response limit + let foo = new Foo({fooVal:i, blob: Buffer.from(`hello query ${i}`), padding: Buffer.alloc(3.5E5)}); + all_foos.push(foo); + await foo.save(); + } + const N = 10; + for (let i = 0; i < N; i++) { + await new Bar({barVal:i, blob: Buffer.from(`hello query ${i}`), }).save(); + await new IndexedString({someN:i, someString:`string number ${i}`, someOtherString:'constant value' }).save(); + await new IndexedTs({someN:i, someTs:(new Date(i*1e7)) }).save(); + await new IndexedNumberAndBinary({num:i, blob: Buffer.from(`hello query ${i%4}`), }).save(); + await new Ambiguous().save(); + } + + t.after(async () => { + await table.deleteTable(); + table.destroyConnection(); + }); + + await t.test('listAllIds', async t => { + const allFoos = []; + for await (const x of Foo.listAllIds({Limit:2})) { + allFoos.push(x); + t.equal(x.split('.')[1], 'foo'); + } + + const allBars = []; + for await (const x of Bar.listAllIds()) { + allBars.push(x); + t.equal(x.split('.')[1], 'bar'); + } + + t.equal(allFoos.length, all_foos.length); + t.equal(allBars.length, 10); + t.ok(allFoos.every(x => x.split('.')[1] === 'foo')); + t.ok(allBars.every(x => x.split('.')[1] === 'bar')); + + t.end(); + }); + + await t.test('rawQueryOneId', async t => { + const id = await Foo.rawQueryOneId({ + IndexName:'type', + KeyConditionExpression:'#typeFieldName = :type', + ExpressionAttributeValues: { ':type': 'namespace.foo' }, + ExpressionAttributeNames: { '#typeFieldName': 'type' } + }); + t.equal(id.split('.')[1], 'foo'); + }); + + await t.test('rawQueryOne', async t => { + t.test('on type index', async t => { + const foo = await Foo.rawQueryOne({ + IndexName:'type', + KeyConditionExpression:'#typeFieldName = :type', + ExpressionAttributeValues: { ':type': 'namespace.foo' }, + ExpressionAttributeNames: { '#typeFieldName': 'type' } + }); + t.equal(foo.constructor, Foo, 'constructor should be Foo'); + t.equal(foo instanceof Foo, true, 'should be an instance of Foo'); + + const nonExistent = await Foo.rawQueryOne({ + IndexName:'type', + KeyConditionExpression:'#typeFieldName = :type', + ExpressionAttributeValues: { ':type': 'namespace.doesNotExist' }, + ExpressionAttributeNames: { '#typeFieldName': 'type' } + }); + t.equal(nonExistent, null, 'returns null for no matches'); + }); + t.test('on string index ', async t => { + const indexedString = await IndexedString.rawQueryOne({ + IndexName:'someString', + KeyConditionExpression:'someString = :value', + ExpressionAttributeValues: { ':value': 'string number 4' } + }); + t.equal(indexedString.constructor, (new IndexedString()).constructor, 'should have correct constructor'); + t.equal(indexedString.someN, 4, 'should have other properties set correctly'); + }); + t.test('on binary index ', async t => { + const nb = await IndexedNumberAndBinary.rawQueryOne({ + IndexName:'myBinaryIndex', + // 'blob' is a banned name, so need to use ExpressionAttributeNames... + KeyConditionExpression:'#fieldName = :value', + ExpressionAttributeValues: { ':value': Buffer.from('hello query 3') }, + ExpressionAttributeNames: { '#fieldName': 'blob' } + }); + t.equal(nb.constructor, (new IndexedNumberAndBinary()).constructor, 'should have correct constructor'); + t.equal(nb.num, 3, 'should return the lowest in sorted order'); + }); + }); + + await t.test('getById', t => { + t.rejects(Foo.getById(null), 'should reject null id'); + t.rejects(Foo.getById(''), 'should reject empty id'); + t.rejects(Foo.getById(123), 'should reject numeric id'); + t.end(); + }); + + await t.test('table.getById', async t => { + t.rejects(table.getById('blegh.someid'), new Error('Table has no matching model type for id "blegh.someid", so it cannot be loaded.'), 'should reject unknown type'); + t.rejects(table.getById('ambiguous.bar.someid'), new Error('Table has multiple ambiguous model types for id "ambiguous.bar.someid", so it cannot be loaded generically.'), 'should reject ambiguous type'); + const foo = await table.getById(all_foos[0].id); + t.equal(foo.constructor, Foo, 'should get the correct type'); + t.equal(foo.id, all_foos[0].id, 'should get the correct document'); + }); + + await t.test('getByIds', async t => { + await t.rejects(Foo.getByIds([null]), 'should reject null id'); + t.match(await Foo.getByIds(['nonexistent']), [null], 'should return null for nonexistent id'); + t.match(await Foo.getByIds(['nonexistent', all_foos[0].id]), [null, all_foos[0]], 'should return null along with extant model'); + const foos = await Foo.getByIds(all_foos.map(f => f.id)); + t.equal(foos.length, all_foos.length, 'should return all models'); + t.match(foos.map(f => f?.id), all_foos.map(f => f?.id), 'should return all models in order'); + await t.rejects(Foo.getByIds(''), new Error('Invalid ids: must be array of strings of nonzero length.'), 'should reject non-array argument'); + t.end(); + }); + + t.test('aborting getByIds', async t => { + const ac0 = new AbortController(); + ac0.abort(new Error('my reason 0 ')); + // the AWS SDk doesn't propagate the abort reason (but it would be nice if it did in the future) + t.rejects(Foo.getByIds(all_foos.map(f => f.id), {abortSignal: ac0.signal}), {name:'AbortError', message:'Request aborted'}, 'getByIds should be abortable with an AbortController that is already aborted'); + + const ac1 = new AbortController(); + // the AWS SDk doesn't propagate the abort reason (but it would be nice if it did in the future) + t.rejects(Foo.getByIds(all_foos.map(f => f.id), {abortSignal: ac1.signal}), {name:'AbortError', message:'Request aborted'}, 'getByIds should be abortable with an AbortController signal immediately'); + ac1.abort(new Error('my reason')); + + const ac2 = new AbortController(); + t.rejects(Foo.getByIds(all_foos.map(f => f.id), {abortSignal: ac2.signal}), {name:'AbortError', message:'Request aborted'}, 'getByIds should be abortable with an AbortController signal asynchronously'); + setTimeout(() => { + ac2.abort(new Error('my reason 2')); + }, 1); + t.end(); + }); + + await t.test('rawQueryIds', async t => { + t.test('on type index', async t => { + const foos = await arrayFromAsync(Foo.rawQueryIds({ + IndexName:'type', + KeyConditionExpression:'#typeFieldName = :type', + ExpressionAttributeValues: { ':type': 'namespace.foo' }, + ExpressionAttributeNames: { '#typeFieldName': 'type' } + })); + t.equal(foos.length, all_foos.length, 'should return all N of this type'); + t.type(foos[0], 'string', 'should return String IDs'); + }); + t.end(); + }); + + await t.test('rawQuery', async t => { + t.test('on type index', async t => { + const foos = await arrayFromAsync(Foo.rawQuery({ + IndexName:'type', + KeyConditionExpression:'#typeFieldName = :type', + ExpressionAttributeValues: { ':type': 'namespace.foo' }, + ExpressionAttributeNames: { '#typeFieldName': 'type' } + })); + t.equal(foos.length, all_foos.length, 'should return all N of this type'); + t.equal(foos[0].constructor, (new Foo()).constructor, 'should have the correct constructor'); + }); + t.test('on string index ', async t => { + const indexedStrings = await arrayFromAsync(IndexedString.rawQuery({ + IndexName:'someString', + KeyConditionExpression:'someString = :value', + ExpressionAttributeValues: { ':value': 'string number 4' } + })); + t.equal(indexedStrings.length, 1, 'should return one match'); + t.equal(indexedStrings[0].constructor, (new IndexedString()).constructor, 'should have the correct constructor'); + t.equal(indexedStrings[0].someN, 4, 'should have other properties set correctly'); + }); + t.test('on binary index ', async t => { + const nb = await arrayFromAsync(IndexedNumberAndBinary.rawQuery({ + IndexName:'myBinaryIndex', + KeyConditionExpression:'#fieldName = :value', + ExpressionAttributeValues: { ':value': Buffer.from('hello query 3') }, + ExpressionAttributeNames: { '#fieldName': 'blob' } + })); + t.equal(nb.length, 2, 'should return two matches'); + t.equal(nb[0].constructor, (new IndexedNumberAndBinary()).constructor, 'should have correct constructor'); + t.equal(nb[0].num, 3, 'should return the lowest in sorted order'); + }); + t.end(); + }); + + await t.test('query() api', async t => { + // TODO: + // * tests for $gt $lt conditions on hash-only indexes to make sure we reject with a nice error (currently the error comes from dynamodb doc client and is not very helpful) + t.test('queryMany', async t => { + t.test('on type index', async t => { + const foos = await Foo.queryMany({ type: 'namespace.foo' }); + t.equal(foos.length, all_foos.length, 'should return all N of this type'); + t.equal(foos[0].constructor, (new Foo()).constructor, 'should have the correct constructor'); + t.rejects(Foo.queryMany({ type: 123 }), {message:'Value does not match schema for type: must be string.'}, 'passing an incompatible value should reject'); + }); + t.test('on string index ', async t => { + const indexedStrings = await IndexedString.queryMany({someString: 'string number 4'}); + t.equal(indexedStrings.length, 1, 'should return one match'); + t.equal(indexedStrings[0].constructor, (new IndexedString()).constructor, 'should have the correct constructor'); + t.equal(indexedStrings[0].someN, 4, 'should have other properties set correctly'); + }); + t.test('on ts index ', async t => { + const indexedStrings = await IndexedTs.queryMany({someTs: new Date(2e7)}); + t.equal(indexedStrings.length, 1, 'should return one match'); + t.equal(indexedStrings[0].constructor, (new IndexedTs()).constructor, 'should have the correct constructor'); + t.equal(indexedStrings[0].someN, 2, 'should have other properties set correctly'); + }); + t.test('on binary index ', async t => { + const nb = await IndexedNumberAndBinary.queryMany({ 'blob': Buffer.from('hello query 3') }); + t.equal(nb.length, 2, 'should return two matches'); + t.equal(nb[0].constructor, (new IndexedNumberAndBinary()).constructor, 'should have correct constructor'); + t.equal(nb[0].num, 3, 'should return the lowest in sorted order'); + }); + t.test('on binary index with sort ', async t => { + const nb = await IndexedNumberAndBinary.queryMany({ 'blob': Buffer.from('hello query 3'), 'num':7 }); + t.equal(nb.length, 1, 'should return one match'); + t.equal(nb[0].constructor, (new IndexedNumberAndBinary()).constructor, 'should have correct constructor'); + t.equal(nb[0].num, 7, 'should return the matching item'); + }); + t.test('invalid queries', async t => { + t.rejects(Foo.queryMany({type: 'namespace.foo', fooVal:3 }), {message:'Unsupported query: "{ type: \'namespace.foo\', fooVal: 3 }". No index found for query fields [type, fooVal]'}, 'rejects non-queryable extra parameters'); + t.rejects(IndexedNumberAndBinary.queryMany({'blob': Buffer.from('hello query 3'), 'num':7, id:'123' }), {message:'Unsupported query: "{ blob: , num: 7, id: \'123\' }" Queries must have at most two properties to match against index hash and range attributes.'}, 'rejects more than two parameters'); + t.rejects(IndexedNumberAndBinary.queryMany({num:{$gt:0, $lt:2}}), {message:'Only a single $gt/$gte/$lt/$lte condition is supported in the simple query api.'}, 'rejects multiple conditions'); + }); + t.test('multiple possible indexes', async t => { + const nb = await IndexedNumberAndBinary.queryMany({ num:7 }); + t.equal(nb.length, 1, 'should return one match'); + t.equal(nb[0].constructor, (new IndexedNumberAndBinary()).constructor, 'should have correct constructor'); + t.equal(nb[0].num, 7, 'should return correct item'); + }); + t.test('query conditions', async t => { + t.test('$gt', async t => { + const r = await Bar.queryMany({ type:'ambiguous.bar', barVal: { $gt: 7 } }); + t.equal(r.length, N-8, `should return ${N-8} matches`); + t.equal(r[0].constructor, Bar, 'should have correct constructor'); + t.equal(r[0].barVal, 8, 'should return in ascending order'); + t.end(); + }); + t.test('$gte', async t => { + const r = await Bar.queryMany({ type:'ambiguous.bar', barVal: { $gte: 7 } }); + t.equal(r.length, N-7, `should return ${N-7} matches`); + t.equal(r[0].constructor, Bar, 'should have correct constructor'); + t.equal(r[0].barVal, 7, 'should return in ascending order'); + t.end(); + }); + t.test('$lt', async t => { + const r = await Bar.queryMany({ type:'ambiguous.bar', barVal: { $lt: 7 } }); + t.equal(r.length, 7, 'should return 7 matches'); + t.equal(r[0].constructor, Bar, 'should have correct constructor'); + t.equal(r[0].barVal, 0, 'should return in ascending order'); + t.end(); + }); + t.test('$lte', async t => { + const r = await Bar.queryMany({ type:'ambiguous.bar', barVal: { $lte: 7 } }); + t.equal(r.length, 8, 'should return 8 matches'); + t.equal(r[0].constructor, Bar, 'should have correct constructor'); + t.equal(r[0].barVal, 0, 'should return in ascending order'); + t.end(); + }); + await t.test('$unsupported', async t => { + await t.rejects(Bar.queryMany({ type:'ambiguous.bar', barVal: { $unsupported: 7 } }), {message:'Condition "$unsupported" is not supported.'}, 'should reject unsupported $condition'); + }); + t.end(); + }); + t.test('aborting queryMany', async t => { + const ac0 = new AbortController(); + ac0.abort(new Error('my reason 0')); + t.rejects(Foo.queryMany({ type: 'namespace.foo' }, {abortSignal: ac0.signal}), {name:'AbortError', message:'Request aborted'}, 'queryMany should be abortable with an AbortController that is already aborted'); + + const ac1 = new AbortController(); + // the AWS SDk doesn't propagate the abort reason (but it would be nice if it did in the future) + t.rejects(Foo.queryMany({ type: 'namespace.foo' }, {abortSignal: ac1.signal}), {name:'AbortError', message:'Request aborted'}, 'queryMany should be abortable with an AbortController signal immediately'); + ac1.abort(new Error('my reason')); + + const ac2 = new AbortController(); + t.rejects(Foo.queryMany({ type: 'namespace.foo' }, {abortSignal: ac2.signal}), {name:'AbortError', message:'Request aborted'}, 'queryMany should be abortable with an AbortController signal asynchronously'); + setTimeout(() => { + ac2.abort(new Error('my reason 2')); + }, 1); + + // check that aborting after completion doesn't do anything bad: + const ac3 = new AbortController(); + const foos = await Foo.queryMany({ type: 'namespace.foo' }, {abortSignal: ac3.signal}); + ac3.abort(new Error('my reason 3')); + t.ok(foos[0] instanceof Foo, 'should have still returned genuine bona fide Foos'); + + t.end(); + }); + t.test('with startAfter on hash and sort index', async t => { + let startAfter; + let count = 0; + while(count < all_foos.length) { + const models = await Foo.queryMany({type: 'namespace.foo'}, {limit:7, ...(startAfter && {startAfter}) }); + t.equal(models.length, Math.min(7, all_foos.length - count), '.limit:7, startAfter:previous, should always return the right number of models until there are none left'); + t.equal(models[0].type, 'namespace.foo', 'should return models of the right type'); + startAfter = models[models.length-1]; + count += models.length; + } + const no_models = await Foo.queryMany({type: 'namespace.foo'}, {limit:1, startAfter }); + t.equal(no_models.length, 0, 'should not return anything on startAfter last'); + t.end(); + }); + t.test('with startAfter on hash-only index', async t => { + let startAfter; + let count = 0; + while(count < N) { + const models = await IndexedString.queryMany({someOtherString: 'constant value'}, {limit:1, ...(startAfter && {startAfter}) }); + t.equal(models.length, 1, '.limit:1, startAfter:previous, should always return a model'); + t.equal(models[0].type, 'namespace.indexedString', 'should return models of the right type'); + startAfter = models[0]; + count += models.length; + } + const no_models = await IndexedString.queryMany({someOtherString: 'constant value'}, {limit:1, startAfter }); + t.equal(no_models.length, 0, 'should not return anything on startAfter last'); + t.end(); + }); + await t.test('with invalid startAfter', async t => { + await t.rejects(Foo.queryMany({type: 'namespace.foo'}, {limit:1, startAfter: {id:'123', type:'namespace.foo'} }), {message:'options.startAfter must be a Model_namespace.foo model instance. To specify ExclusiveStartKey directly use options.rawQueryOptions.ExclusiveStartKey instead.'}, 'should reject non-instance startAfter'); + + t.end(); + }); + t.end(); + }); + + t.test('queryManyIds', async t => { + const allFooIds = await Foo.queryManyIds({ type: 'namespace.foo' }); + t.match(allFooIds.sort(), all_foos.map(f => f.id).sort(), 'should return all IDs'); + t.end(); + }); + + t.test('queryOne', async t => { + const aFoo = await Foo.queryOne({ type: 'namespace.foo' }); + t.equal(aFoo.constructor, (new Foo()).constructor, 'should have the correct constructor'); + t.end(); + }); + t.test('aborting queryOne', async t => { + const ac0 = new AbortController(); + ac0.abort(new Error('my reason 0')); + t.rejects(Foo.queryOne({ type: 'namespace.foo' }, {abortSignal: ac0.signal}), {name:'AbortError', message:'Request aborted'}, 'queryOne should be abortable with an AbortController that is already aborted'); + + const ac1 = new AbortController(); + // the AWS SDk doesn't propagate the abort reason (but it would be nice if it did in the future) + t.rejects(Foo.queryOne({ type: 'namespace.foo' }, {abortSignal: ac1.signal}), {name:'AbortError', message:'Request aborted'}, 'queryOne should be abortable with an AbortController signal immediately'); + ac1.abort(new Error('my reason')); + + const ac2 = new AbortController(); + t.rejects(Foo.queryOne({ type: 'namespace.foo' }, {abortSignal: ac2.signal}), {name:'AbortError', message:'Request aborted'}, 'queryOne should be abortable with an AbortController signal asynchronously'); + setTimeout(() => { + ac2.abort(new Error('my reason 2')); + }, 1); + + // check that aborting after completion doesn't do anything bad: + const ac3 = new AbortController(); + const aFoo = await Foo.queryOne({ type: 'namespace.foo' }, {abortSignal: ac3.signal}); + ac3.abort(new Error('my reason 3')); + t.ok(aFoo instanceof Foo, 'should have still returned a genuine bona fide Foo'); + + t.end(); + }); + + t.test('queryOneId', async t => { + const aFooId = await Foo.queryOneId({ type: 'namespace.foo' }); + t.ok(all_foos.filter(x => x.id === aFooId).length === 1, 'should return a foo ID'); + t.end(); + }); + await t.test('aborting queryOneId', async t => { + const ac1 = new AbortController(); + // the AWS SDk doesn't propagate the abort reason (but it would be nice if it did in the future) + t.rejects(Foo.queryOneId({ type: 'namespace.foo' }, {abortSignal: ac1.signal}), {name:'AbortError', message:'Request aborted'}, 'queryOneId should be abortable with an AbortController signal immediately'); + ac1.abort(new Error('my reason')); + + const ac2 = new AbortController(); + t.rejects(Foo.queryOneId({ type: 'namespace.foo' }, {abortSignal: ac2.signal}), {name:'AbortError', message:'Request aborted'}, 'queryOneId should be abortable with an AbortController signal asynchronously'); + setTimeout(() => { + ac2.abort(new Error('my reason 2')); + }, 0); + t.end(); + }); + + // await t.test('querying via a model of the wrong type', async t => { + // console.log('starting query-wrong-type test'); + // const result = t.rejects(Bar.queryMany({type:'namespace.foo'}), {message:'Document does not match schema for ambiguous.bar. The loaded document has a different type "namespace.foo", and the schema is incompatible: must have required property \'barVal\'.'}, 'should throw if the query returns a document of an incompatible type'); + // console.log('running query-wrong-type test'); + // try { + // await result; + // } catch (e) { + // console.log('this error should not have been thrown!!!', e); + // } + // console.log('finished query-wrong-type test'); + // t.end(); + // }); + + t.end(); + }); + + await t.test('add missing indexes', async t => { + const table3 = DynamoDM.Table({ name: 'test-compatible-indexes'}); + t.teardown(async () => { + await table3.deleteTable(); + table3.destroyConnection(); + }); + await t.test('adding incompatible index types', async t => { + const table2 = DynamoDM.Table({ name: 'test-table-incompidxtypes'}); + table2.model(FooSchema); + table2.model(BarSchema); + table2.model(IndexedStringSchema); + table2.model(IndexedNumberAndBinarySchema); + + table2.model(IncompatibleStringSchema); + table2.model(CompatibleExtraStringSchema); + + await t.rejects(table2.ready(), /Schema\(s\) .* define incompatible types \(S,N\) for "\.someString" in index\(es\) "someString, someString"\./, '.ready() should fail with incompatible index types'); + }); + + await t.test('adding incompatible indexes', async t => { + const table2 = DynamoDM.Table({ name: 'test-incompat-idx'}); + table2.model(FooSchema); + table2.model(BarSchema); + table2.model(IndexedStringSchema); + table2.model(IndexedNumberAndBinarySchema); + + table2.model(IncompatibleString2Schema); + table2.model(CompatibleExtraStringSchema); + + await t.rejects(table2.ready(), /Schema\(s\) .* define incompatible versions of index "someString"\./, '.ready() should fail with incompatible indexes'); + }); + + await t.test('adding compatible indexes', async t => { + table3.model(FooSchema); + table3.model(BarSchema); + table3.model(IndexedStringSchema); + table3.model(IndexedNumberAndBinarySchema); + + const CompatibleExtraString = table3.model(CompatibleExtraStringSchema); + + // normally .ready() doesn't ordinarily wait for indexes to actually be ready, it just starts creating them, but in this case we need to wait + await table3.ready({waitForIndexes: true}); + + // even with waitForIndexes we seem to need a short delay with dynamodb-local here :( + await new Promise(r => setTimeout(r, 600)); + + // add some models + for (var i = 0; i < 13; i++) { + await new CompatibleExtraString({num:i, otherString: `string query ${i%4}`, }).save(); + } + + // check that we can query for them: + await t.test('rawQuery on added index', async t => { + await t.test('on string index ', async t => { + const extraStrings = await arrayFromAsync(CompatibleExtraString.rawQuery({ + IndexName:'otherString', + KeyConditionExpression:'otherString = :value', + ExpressionAttributeValues: { ':value': 'string query 2' } + })); + t.equal(extraStrings.length, 3, 'should return three matches'); + t.equal(extraStrings[0].constructor, (new CompatibleExtraString()).constructor, 'should have the correct constructor'); + t.equal(extraStrings[0].num, 2, 'should return values in sorted order'); + t.equal(extraStrings[1].num, 6, 'should return values in sorted order'); + t.equal(extraStrings[2].num, 10, 'should return values in sorted order'); + t.end(); + }); + t.end(); + }); + t.end(); + }); + t.end(); + }); + + t.end(); +}); + +t.end();