From 48c5e4141f765f167e2e7a46731cd07609ba751a Mon Sep 17 00:00:00 2001 From: Thomas Taylor Date: Sat, 28 Mar 2026 17:56:09 +0000 Subject: [PATCH 01/14] New: Add conf-gen, lang-check and schema-check commands --- bin/conf-gen.js | 109 +++++++++++++++++++++++ bin/lang-check.js | 115 ++++++++++++++++++++++++ bin/schema-check.js | 37 ++++++++ lib/utils/checkSchemaForDuplicates.js | 15 ++++ lib/utils/storeDefaults.js | 24 +++++ package.json | 1 + tests/checkSchemaForDuplicates.spec.js | 70 +++++++++++++++ tests/storeDefaults.spec.js | 118 +++++++++++++++++++++++++ 8 files changed, 489 insertions(+) create mode 100644 bin/conf-gen.js create mode 100644 bin/lang-check.js create mode 100644 bin/schema-check.js create mode 100644 lib/utils/checkSchemaForDuplicates.js create mode 100644 lib/utils/storeDefaults.js create mode 100644 tests/checkSchemaForDuplicates.spec.js create mode 100644 tests/storeDefaults.spec.js diff --git a/bin/conf-gen.js b/bin/conf-gen.js new file mode 100644 index 0000000..30505d9 --- /dev/null +++ b/bin/conf-gen.js @@ -0,0 +1,109 @@ +import SimpleCliCommand from '../lib/SimpleCliCommand.js' +import storeDefaults from '../lib/utils/storeDefaults.js' +import fs from 'node:fs' +import fsp from 'node:fs/promises' +import { globSync } from 'glob' +import path from 'node:path' +import { pathToFileURL } from 'node:url' + +export default class Confgen extends SimpleCliCommand { + get config () { + return { + ...super.config, + description: 'Generates a template config file which can be populated with required values', + options: [ + ['--env ', 'The environment to write the config for (defaults to NODE_ENV)'], + ['--defaults', 'Include default values'], + ['--replace', 'Override any existing values'], + ['--update', 'Update existing configuration with any missing values'] + ] + } + } + + async runTask () { + const env = this.options.env || process.env.NODE_ENV + if (!env) { + return console.log('ERROR: environment must be specified via --env or NODE_ENV\n') + } + if (this.options.replace && this.options.update) { + return console.log('ERROR: --update and --replace cannot both be specified, please choose one and run the utility again') + } + if (this.options.defaults) { + console.log('Default values will be included') + } + const confDir = path.resolve('conf') + const outpath = path.join(confDir, `${env}.config.js`) + const configJson = {} + + let isExistingConfig = false + let existingConfig + try { + existingConfig = (await import(pathToFileURL(outpath).href)).default + isExistingConfig = true + } catch (e) { + console.log(`No config found for NODE_ENV '${env}'. File will be written to ${outpath}\n`) + } + if (isExistingConfig) { + const msg = `Config already exists for NODE_ENV '${env}'. ` + if (this.options.replace) { + console.log(`${msg}All existing values will be replaced.`) + } else if (this.options.update) { + console.log(`${msg}Any missing values will be added.`) + Object.assign(configJson, existingConfig) + } else { + return console.log(`${msg}Must specifiy --replace or --update to make changes.`) + } + } + try { + this.generateConfig(configJson) + await fsp.mkdir(confDir, { recursive: true }) + await fsp.writeFile(outpath, `export default ${JSON.stringify(configJson, null, 2)};`) + console.log(`Config file written successfully to ${outpath}.\n`) + this.logRequired(configJson) + } catch (e) { + console.log(`ERROR: Failed to write ${outpath}\n${e}`) + } + } + + logRequired (configJson) { + const requiredAttrs = [] + Object.entries(configJson).forEach(([name, config]) => { + Object.entries(config).forEach(([key, value]) => value === null && requiredAttrs.push(`${name}.${key}`)) + }) + if (requiredAttrs.length) { + console.log('Note: the following required attributes have been given a value of null and must be set for the application to run:\n') + console.log(requiredAttrs.join('\n')) + console.log('') + } + } + + getDeps () { + try { + const depRoot = `${process.cwd()}/node_modules/`.replaceAll(path.sep, path.posix.sep) + return globSync(`${depRoot}**/adapt-authoring.json`).map(f => { + const dirname = path.dirname(f) + return [dirname.replace(depRoot, ''), dirname] + }) + } catch (e) { + console.log('Failed to load package', e) + return [] + } + } + + generateConfig (configJson) { + for (const [name, dir] of this.getDeps()) { + let schema + try { + schema = JSON.parse(fs.readFileSync(path.resolve(dir, 'conf/config.schema.json'))) + } catch (e) { + continue + } + if (!configJson[name]) { + configJson[name] = {} + } + storeDefaults(schema, configJson[name], { replace: this.options.replace, useDefaults: this.options.defaults }) + } + // remove any empty objects + Object.entries(configJson).forEach(([key, config]) => !Object.keys(config).length && delete configJson[key]) + } +} diff --git a/bin/lang-check.js b/bin/lang-check.js new file mode 100644 index 0000000..67d7226 --- /dev/null +++ b/bin/lang-check.js @@ -0,0 +1,115 @@ +import SimpleCliCommand from '../lib/SimpleCliCommand.js' +import fs from 'node:fs/promises' +import { glob } from 'glob' +import path from 'node:path' + +export default class Langcheck extends SimpleCliCommand { + get config () { + return { + ...super.config, + description: 'Checks for unused and missing language strings' + } + } + + async runTask () { + const root = `${process.cwd().replaceAll(path.sep, '/')}/node_modules` + + this.underline('Language String Check') + + const translatedStrings = await this.getTranslatedStrings(root) + console.log('\n Languages found:') + Object.keys(translatedStrings).forEach(l => console.log(' -', l)) + + for (const lang of Object.keys(translatedStrings)) { + console.log('\n') + this.underline(`Language: ${lang}`.toUpperCase()) + + const langStrings = translatedStrings[lang] + const usedStrings = await this.getUsedStrings(root, langStrings) + const unusedStrings = Object.entries(langStrings).filter(([k, v]) => !k.startsWith('error.') && !v).map(([k]) => k) + const missingStrings = Object.entries(usedStrings) + .filter(([key]) => !langStrings[key] && !key.startsWith('error') && key !== 'app.js') + .map(([key, locations]) => `${key}${locations}`) + + console.log() + if (unusedStrings.length) { + this.logStrings(unusedStrings, 'translated strings unreferenced in the code') + console.log() + } + if (missingStrings.length) { + this.logStrings(missingStrings, 'strings without translation') + console.log() + } + if (!unusedStrings.length && !missingStrings.length) { + console.log('✓ No issues found!\n') + } + this.underline(`Summary:\n - ${unusedStrings.length} unused language strings found\n - ${missingStrings.length} missing language strings found`) + } + console.log() + } + + underline (s = '', topLine = true) { + const line = ''.padEnd(80, '-') + console.log(`${topLine ? line + '\n' : ''} ${s}\n${line}`) + } + + async getTranslatedStrings (root) { + const langPacks = await glob(`${root}/adapt-authoring-*/lang`) + const keyMap = {} + await Promise.all(langPacks.map(async langDir => { + const files = await glob('**/*.json', { cwd: langDir, absolute: true }) + await Promise.all(files.map(async f => { + const keys = JSON.parse(await fs.readFile(f)) + const relative = path.relative(langDir, f) + const parts = relative.replace(/\.json$/, '').split(path.sep) + const lang = parts[0] + const prefix = parts.length > 1 ? parts.slice(1).join('.') + '.' : '' + if (!keyMap[lang]) keyMap[lang] = {} + Object.keys(keys).forEach(k => { + keyMap[lang][`${prefix}${k}`] = false + }) + })) + })) + return keyMap + } + + async getUsedStrings (root, translatedStrings) { + const usedStrings = {} + const errorFiles = await glob('adapt-authoring-*/errors/*.json', { cwd: root, absolute: true }) + await Promise.all(errorFiles.map(async f => { + Object.keys(JSON.parse((await fs.readFile(f)))).forEach(e => { + const key = `error.${e}` + if (!usedStrings[key]) usedStrings[key] = new Set() + usedStrings[key].add(f.replace(root, '').split('/')[1]) // only add module name for errors + }) + })) + const sourceFiles = await glob('adapt-authoring-*/**/*.@(js|hbs)', { cwd: root, absolute: true, ignore: ['**/node_modules/**', '**/*.spec.js', '**/tests/**'] }) + + await Promise.all(sourceFiles.map(async f => { + const contents = (await fs.readFile(f)).toString() + const allMatches = contents.matchAll(/(['"`])((?:app|error)\.[\w.]+)\1/g) + + for (const m of allMatches) { + const key = m[2] + if (Object.hasOwn(translatedStrings, key)) { + translatedStrings[key] = true + } + if (!usedStrings[key]) usedStrings[key] = new Set() + usedStrings[key].add(f.replace(root, '')) + } + })) + Object.entries(usedStrings).forEach(([k, set]) => { + usedStrings[k] = `${Array.from(set).map(s => `\n ${s}`).join('')}` + }) + return usedStrings + } + + logStrings (strings, message) { + if (!strings.length) { + return console.log(`✓ No ${message}`) + } + this.underline(`Found ${strings.length} ${message}`) + console.log(`${strings.map(s => `\n- ${s}`).join('')}`) + process.exitCode = 1 + } +} diff --git a/bin/schema-check.js b/bin/schema-check.js new file mode 100644 index 0000000..84bf888 --- /dev/null +++ b/bin/schema-check.js @@ -0,0 +1,37 @@ +import SimpleCliCommand from '../lib/SimpleCliCommand.js' +import checkSchemaForDuplicates from '../lib/utils/checkSchemaForDuplicates.js' + +export default class Schemacheck extends SimpleCliCommand { + get config () { + return { + ...super.config, + description: 'Checks for duplicate schema properties' + } + } + + async runTask () { + console.log('Checking for duplicate schema definitions.\n') + + process.env.ADAPT_AUTHORING_LOGGER__mute = 'true' + + const { App } = await import('adapt-authoring-core') + const app = await App.instance.onReady() + const schema = await app.waitForModule('jsonschema') + + await Promise.allSettled(Object.keys(schema.schemaPaths).map(async s => { + const usedKeys = {} + const hierarchy = await schema.loadSchemaHierarchy(s) + hierarchy.forEach(h => checkSchemaForDuplicates(h, usedKeys)) + const duplicates = Object.entries(usedKeys).filter(([key, uses]) => uses.length > 1) + + if (duplicates.length) { + console.log(`Schema '${s}' contains duplicate definitions for the following properties:`) + duplicates.forEach(([prop, schemas]) => console.log(` - ${prop}: ${schemas}`)) + console.log('') + process.exitCode = 1 + } + })) + if (process.exitCode !== 1) console.log('No duplicates found.') + process.exit() + } +} diff --git a/lib/utils/checkSchemaForDuplicates.js b/lib/utils/checkSchemaForDuplicates.js new file mode 100644 index 0000000..b85dba8 --- /dev/null +++ b/lib/utils/checkSchemaForDuplicates.js @@ -0,0 +1,15 @@ +/** + * Collects property definitions from a schema into a tracking object, + * recording which schema ($anchor) defines each property. + * @param {Object} schema - A JSON schema (may use $patch or $merge format) + * @param {Object} usedKeys - Map of property name to array of schema $anchors that define it + */ +export default function checkSchemaForDuplicates (schema, usedKeys) { + const props = schema.properties ?? schema?.$patch?.with?.properties ?? schema?.$merge?.with?.properties + if (!props) return + Object.keys(props).forEach(p => { + if (p === '_globals') return + if (!usedKeys[p]) usedKeys[p] = [] + usedKeys[p].push(schema.$anchor) + }) +} diff --git a/lib/utils/storeDefaults.js b/lib/utils/storeDefaults.js new file mode 100644 index 0000000..804900f --- /dev/null +++ b/lib/utils/storeDefaults.js @@ -0,0 +1,24 @@ +/** + * Populates a defaults object from a JSON schema's properties. + * Required properties are set to null, optional properties use their default value. + * @param {Object} schema - JSON schema with a `properties` object and optional `required` array + * @param {Object} [defaults={}] - Existing defaults to populate + * @param {Object} [options={}] + * @param {Boolean} [options.replace=false] - Whether to overwrite existing values + * @param {Boolean} [options.useDefaults=false] - Whether to include default values + * @returns {Object} The populated defaults object + */ +export default function storeDefaults (schema, defaults = {}, { replace = false, useDefaults = false } = {}) { + return Object.entries(schema.properties).reduce((memo, [attr, config]) => { + if (config.type === 'object' && config.properties) { + return { ...memo, [attr]: storeDefaults(config, memo, { replace, useDefaults }) } + } + const isRequired = schema?.required?.includes(attr) ?? false + const shouldUpdate = replace || !Object.hasOwn(memo, attr) + const hasDefault = useDefaults && Object.hasOwn(config, 'default') + if (shouldUpdate && (hasDefault || isRequired)) { + memo[attr] = isRequired ? null : config.default + } + return memo + }, defaults) +} diff --git a/package.json b/package.json index 09edf61..a2e2026 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "repository": "github:adapt-security/at-utils", "dependencies": { "commander": "^14.0.3", + "glob": "^13.0.0", "prompts": "^2.4.2", "semver": "^7.7.4" }, diff --git a/tests/checkSchemaForDuplicates.spec.js b/tests/checkSchemaForDuplicates.spec.js new file mode 100644 index 0000000..542ca4d --- /dev/null +++ b/tests/checkSchemaForDuplicates.spec.js @@ -0,0 +1,70 @@ +import { describe, it } from 'node:test' +import assert from 'node:assert/strict' +import checkSchemaForDuplicates from '../lib/utils/checkSchemaForDuplicates.js' + +describe('checkSchemaForDuplicates', () => { + it('tracks properties with their schema anchor', () => { + const usedKeys = {} + checkSchemaForDuplicates({ + $anchor: 'base', + properties: { title: {}, body: {} } + }, usedKeys) + assert.deepEqual(usedKeys.title, ['base']) + assert.deepEqual(usedKeys.body, ['base']) + }) + + it('appends to existing entries for duplicate properties', () => { + const usedKeys = { title: ['base'] } + checkSchemaForDuplicates({ + $anchor: 'extended', + properties: { title: {}, description: {} } + }, usedKeys) + assert.deepEqual(usedKeys.title, ['base', 'extended']) + assert.deepEqual(usedKeys.description, ['extended']) + }) + + it('skips _globals property', () => { + const usedKeys = {} + checkSchemaForDuplicates({ + $anchor: 'test', + properties: { _globals: {}, title: {} } + }, usedKeys) + assert.equal(Object.hasOwn(usedKeys, '_globals'), false) + assert.deepEqual(usedKeys.title, ['test']) + }) + + it('handles $patch format', () => { + const usedKeys = {} + checkSchemaForDuplicates({ + $anchor: 'patched', + $patch: { with: { properties: { name: {} } } } + }, usedKeys) + assert.deepEqual(usedKeys.name, ['patched']) + }) + + it('handles $merge format', () => { + const usedKeys = {} + checkSchemaForDuplicates({ + $anchor: 'merged', + $merge: { with: { properties: { name: {} } } } + }, usedKeys) + assert.deepEqual(usedKeys.name, ['merged']) + }) + + it('does nothing when schema has no properties', () => { + const usedKeys = {} + checkSchemaForDuplicates({ $anchor: 'empty' }, usedKeys) + assert.deepEqual(usedKeys, {}) + }) + + it('prefers direct properties over $patch/$merge', () => { + const usedKeys = {} + checkSchemaForDuplicates({ + $anchor: 'both', + properties: { direct: {} }, + $patch: { with: { properties: { patched: {} } } } + }, usedKeys) + assert.deepEqual(usedKeys.direct, ['both']) + assert.equal(Object.hasOwn(usedKeys, 'patched'), false) + }) +}) diff --git a/tests/storeDefaults.spec.js b/tests/storeDefaults.spec.js new file mode 100644 index 0000000..e8479e9 --- /dev/null +++ b/tests/storeDefaults.spec.js @@ -0,0 +1,118 @@ +import { describe, it } from 'node:test' +import assert from 'node:assert/strict' +import storeDefaults from '../lib/utils/storeDefaults.js' + +describe('storeDefaults', () => { + it('sets required properties to null', () => { + const schema = { + required: ['host'], + properties: { + host: { type: 'string' } + } + } + const result = storeDefaults(schema) + assert.equal(result.host, null) + }) + + it('ignores optional properties without defaults by default', () => { + const schema = { + properties: { + port: { type: 'number' } + } + } + const result = storeDefaults(schema) + assert.equal(Object.hasOwn(result, 'port'), false) + }) + + it('includes default values when useDefaults is true', () => { + const schema = { + properties: { + port: { type: 'number', default: 8080 } + } + } + const result = storeDefaults(schema, {}, { useDefaults: true }) + assert.equal(result.port, 8080) + }) + + it('does not include default values when useDefaults is false', () => { + const schema = { + properties: { + port: { type: 'number', default: 8080 } + } + } + const result = storeDefaults(schema) + assert.equal(Object.hasOwn(result, 'port'), false) + }) + + it('does not overwrite existing values by default', () => { + const schema = { + required: ['host'], + properties: { + host: { type: 'string' } + } + } + const result = storeDefaults(schema, { host: 'localhost' }) + assert.equal(result.host, 'localhost') + }) + + it('overwrites existing values when replace is true', () => { + const schema = { + required: ['host'], + properties: { + host: { type: 'string' } + } + } + const result = storeDefaults(schema, { host: 'localhost' }, { replace: true }) + assert.equal(result.host, null) + }) + + it('recurses into nested object properties', () => { + const schema = { + properties: { + db: { + type: 'object', + properties: { + connectionUri: { type: 'string', default: 'mongodb://localhost' } + } + } + } + } + const result = storeDefaults(schema, {}, { useDefaults: true }) + assert.equal(result.db.connectionUri, 'mongodb://localhost') + }) + + it('required takes precedence over default', () => { + const schema = { + required: ['secret'], + properties: { + secret: { type: 'string', default: 'changeme' } + } + } + const result = storeDefaults(schema, {}, { useDefaults: true }) + assert.equal(result.secret, null) + }) + + it('handles schema with no required array', () => { + const schema = { + properties: { + port: { type: 'number', default: 3000 } + } + } + const result = storeDefaults(schema, {}, { useDefaults: true }) + assert.equal(result.port, 3000) + }) + + it('returns the defaults object passed in', () => { + const schema = { + required: ['host'], + properties: { + host: { type: 'string' } + } + } + const defaults = { existing: 'value' } + const result = storeDefaults(schema, defaults) + assert.equal(result, defaults) + assert.equal(result.existing, 'value') + assert.equal(result.host, null) + }) +}) From 11f1531149bc92ebaac6f8550951b67a21ceea09 Mon Sep 17 00:00:00 2001 From: Thomas Taylor Date: Sat, 28 Mar 2026 20:14:18 +0000 Subject: [PATCH 02/14] Breaking: Replace git-based install with GitHub tarball downloads Switch install and update commands from git clone/fetch to downloading GitHub release tarballs. This removes git as a prerequisite, simplifies the update flow (safe staging directory swap instead of in-place git reset), and eliminates several classes of bugs around partial installs. Structural changes: - Unify SimpleCliCommand into CliCommand with opt-out config flags - Remove Utils.js god object; all consumers import utils directly - Extract shared Installer class for install/update orchestration - Extract internalApiRequest and githubHeaders as shared utils - Remove process.exit() from CliCommand.cleanUp - Guard index.js against side-effect execution on import - Consolidate duplicate filter logic in getReleases - Add tests for downloadRelease, swapInstall, getInstalledVersion Files removed: SimpleCliCommand.js, Utils.js, cloneRepo.js, updateRepo.js, installState.js, installState.spec.js New dependency: tar (for cross-platform tarball extraction) Removed prerequisite: git --- bin/conf-gen.js | 4 +- bin/deps-check.js | 14 +- bin/deps-gen.js | 17 +- bin/install.js | 57 +- bin/lang-check.js | 4 +- bin/mail-test.js | 8 +- bin/register-super.js | 11 +- bin/release-notes.js | 4 +- bin/schema-check.js | 4 +- bin/update.js | 15 +- bin/version-check.js | 4 +- index.js | 12 +- lib/CliCommand.js | 104 +- lib/DEFAULT_OPTIONS.js | 4 +- lib/Installer.js | 33 + lib/SimpleCliCommand.js | 11 - lib/UiServer.js | 78 +- lib/Utils.js | 53 - lib/utils/cloneRepo.js | 19 - lib/utils/downloadRelease.js | 27 + lib/utils/getInstalledVersion.js | 16 + lib/utils/getReleases.js | 94 +- lib/utils/githubHeaders.js | 8 + lib/utils/githubRequest.js | 47 +- lib/utils/installLocalModules.js | 16 +- lib/utils/installState.js | 24 - lib/utils/internalApiRequest.js | 23 + lib/utils/registerSuperUser.js | 134 +- lib/utils/swapInstall.js | 18 + lib/utils/updateRepo.js | 12 - package-lock.json | 8936 +++++++++++++++++++++++++++++ package.json | 6 +- tests/downloadRelease.spec.js | 110 + tests/getInstalledVersion.spec.js | 62 + tests/installState.spec.js | 60 - tests/swapInstall.spec.js | 59 + 36 files changed, 9562 insertions(+), 546 deletions(-) create mode 100644 lib/Installer.js delete mode 100644 lib/SimpleCliCommand.js delete mode 100644 lib/Utils.js delete mode 100644 lib/utils/cloneRepo.js create mode 100644 lib/utils/downloadRelease.js create mode 100644 lib/utils/getInstalledVersion.js create mode 100644 lib/utils/githubHeaders.js delete mode 100644 lib/utils/installState.js create mode 100644 lib/utils/internalApiRequest.js create mode 100644 lib/utils/swapInstall.js delete mode 100644 lib/utils/updateRepo.js create mode 100644 package-lock.json create mode 100644 tests/downloadRelease.spec.js create mode 100644 tests/getInstalledVersion.spec.js delete mode 100644 tests/installState.spec.js create mode 100644 tests/swapInstall.spec.js diff --git a/bin/conf-gen.js b/bin/conf-gen.js index 30505d9..69f961c 100644 --- a/bin/conf-gen.js +++ b/bin/conf-gen.js @@ -1,4 +1,4 @@ -import SimpleCliCommand from '../lib/SimpleCliCommand.js' +import CliCommand from '../lib/CliCommand.js' import storeDefaults from '../lib/utils/storeDefaults.js' import fs from 'node:fs' import fsp from 'node:fs/promises' @@ -6,7 +6,7 @@ import { globSync } from 'glob' import path from 'node:path' import { pathToFileURL } from 'node:url' -export default class Confgen extends SimpleCliCommand { +export default class Confgen extends CliCommand { get config () { return { ...super.config, diff --git a/bin/deps-check.js b/bin/deps-check.js index 6327dfa..062a333 100644 --- a/bin/deps-check.js +++ b/bin/deps-check.js @@ -1,12 +1,14 @@ import { readFileSync } from 'node:fs' import { join } from 'node:path' -import SimpleCliCommand from '../lib/SimpleCliCommand.js' -import Utils from '../lib/Utils.js' +import buildPackageIndex from '../lib/utils/buildPackageIndex.js' +import CliCommand from '../lib/CliCommand.js' +import getModuleDirs from '../lib/utils/getModuleDirs.js' +import isModule from '../lib/utils/isModule.js' import { isAdaptModule, deriveExpectedPeerDeps, deriveExpectedDeps, findOutdatedVersions } from '../lib/peerDeps.js' const CORE_PKG = 'adapt-authoring-core' -export default class DepsCheck extends SimpleCliCommand { +export default class DepsCheck extends CliCommand { get config () { return { ...super.config, @@ -25,14 +27,14 @@ export default class DepsCheck extends SimpleCliCommand { let moduleDirs if (this.options.recursive) { - moduleDirs = Utils.getModuleDirs(cwd) + moduleDirs = getModuleDirs(cwd) if (moduleDirs.length === 0) { console.log('No modules found in child directories.') process.exitCode = 1 return } } else { - if (!this.options.versionsOnly && !Utils.isModule(cwd)) { + if (!this.options.versionsOnly && !isModule(cwd)) { console.error(`Not a valid module directory (no adapt-authoring.json found in ${cwd})`) process.exitCode = 1 return @@ -40,7 +42,7 @@ export default class DepsCheck extends SimpleCliCommand { moduleDirs = [cwd] } - const pkgIndex = Utils.buildPackageIndex(join(cwd, this.options.recursive ? '.' : '..')) + const pkgIndex = buildPackageIndex(join(cwd, this.options.recursive ? '.' : '..')) let totalErrors = 0 for (const moduleDir of moduleDirs) { diff --git a/bin/deps-gen.js b/bin/deps-gen.js index 68b73c5..ab1733b 100644 --- a/bin/deps-gen.js +++ b/bin/deps-gen.js @@ -1,12 +1,15 @@ import { readFileSync, writeFileSync, existsSync } from 'node:fs' import { join } from 'node:path' -import SimpleCliCommand from '../lib/SimpleCliCommand.js' -import Utils from '../lib/Utils.js' +import buildPackageIndex from '../lib/utils/buildPackageIndex.js' +import CliCommand from '../lib/CliCommand.js' +import exec from '../lib/utils/exec.js' +import getModuleDirs from '../lib/utils/getModuleDirs.js' +import isModule from '../lib/utils/isModule.js' import { isAdaptModule, deriveExpectedPeerDeps, deriveExpectedDeps, findOutdatedVersions } from '../lib/peerDeps.js' const CORE_PKG = 'adapt-authoring-core' -export default class DepsGen extends SimpleCliCommand { +export default class DepsGen extends CliCommand { get config () { return { ...super.config, @@ -26,14 +29,14 @@ export default class DepsGen extends SimpleCliCommand { let moduleDirs if (this.options.recursive) { - moduleDirs = Utils.getModuleDirs(cwd) + moduleDirs = getModuleDirs(cwd) if (moduleDirs.length === 0) { console.log('No modules found in child directories.') process.exitCode = 1 return } } else { - if (!this.options.versionsOnly && !Utils.isModule(cwd)) { + if (!this.options.versionsOnly && !isModule(cwd)) { console.error(`Not a valid module directory (no adapt-authoring.json found in ${cwd})`) process.exitCode = 1 return @@ -41,7 +44,7 @@ export default class DepsGen extends SimpleCliCommand { moduleDirs = [cwd] } - const pkgIndex = Utils.buildPackageIndex(join(cwd, this.options.recursive ? '.' : '..')) + const pkgIndex = buildPackageIndex(join(cwd, this.options.recursive ? '.' : '..')) const updatedDirs = [] let count = 0 @@ -65,7 +68,7 @@ export default class DepsGen extends SimpleCliCommand { for (const dir of updatedDirs) { console.log(` Running npm update in ${dir}...`) try { - await Utils.exec('npm update', dir) + await exec('npm update', dir) console.log(' ✓ npm update complete') } catch (e) { console.error(` ✗ npm update failed: ${e.message}`) diff --git a/bin/install.js b/bin/install.js index 1b76823..b9b10b8 100644 --- a/bin/install.js +++ b/bin/install.js @@ -1,9 +1,9 @@ import CliCommand from '../lib/CliCommand.js' import DEFAULT_OPTIONS from '../lib/DEFAULT_OPTIONS.js' import fs from 'fs/promises' -import path from 'path' +import Installer from '../lib/Installer.js' +import registerSuperUser from '../lib/utils/registerSuperUser.js' import UiServer from '../lib/UiServer.js' -import Utils from '../lib/Utils.js' export default class Install extends CliCommand { get config () { @@ -11,6 +11,8 @@ export default class Install extends CliCommand { ...super.config, description: 'Installs the application into destination directory', params: { destination: 'The destination folder for the install' }, + checkPrerequisites: true, + getReleaseData: true, options: [ ...DEFAULT_OPTIONS, ['-e --super-email ', 'The admin user email address'], @@ -20,71 +22,30 @@ export default class Install extends CliCommand { } async runTask () { - await this.handleExistingInstall() + await this.checkTargetDir() if (this.options.ui) { return new UiServer(this.options) .on('exit', e => this.cleanUp(e)) } - if (this.options.devMode) { - console.log('IMPORTANT: dev mode flag currently has no effect when running in headless mode\n') - } try { if (!this.options.tag) this.options.tag = await this.getReleaseInput() console.log(`Installing Adapt authoring tool ${this.options.tag} in ${this.options.cwd}`) - await this.cloneRepo() - await Utils.registerSuperUser(this.options) - await Utils.clearInstallState(this.options.cwd) + await new Installer(this.options).install() + await registerSuperUser(this.options) - this.cleanUp() + this.logSuccess('Install completed successfully!') } catch (e) { this.cleanUp(e) } } - async handleExistingInstall () { - const checkpoint = await Utils.getInstallState(this.options.cwd) - if (checkpoint) { - const { resume } = await this.getInput([{ - type: 'confirm', - name: 'resume', - message: 'A previous install was interrupted. Resume from where you left off?', - initial: true - }]) - if (resume) { - this.options.resumeStep = checkpoint.step - return - } - await Utils.clearInstallState(this.options.cwd) - await fs.rm(this.options.cwd, { recursive: true, force: true }) - await fs.mkdir(this.options.cwd, { recursive: true }) - return - } + async checkTargetDir () { let files try { files = await fs.readdir(this.options.cwd) } catch (e) {} if (files?.some(f => f !== 'conf')) throw new Error('Install directory must be empty') } - - async cleanUp (error) { - if (error) { - console.log('Install failed, performing cleanup operation') - try { // for obvious reasons don't remove dest if git clone threw EEXIST - if (error.code !== 'GITCLONEEEXIST') { - console.log('- Removing broken install files') - await fs.rm(this.options.cwd, { recursive: true, force: true }) - if (this.configContents) { - console.log('- Reinstating original config file') - await fs.writeFile(path.resolve(this.options.cwd, `conf/${process.env.NODE_ENV}.config.js`), this.configContents) - } - } - } catch (e) { - console.log('Oh dear, cleanup failed.\n') - console.trace(e) - } - } - super.cleanUp(error) - } } diff --git a/bin/lang-check.js b/bin/lang-check.js index 67d7226..a87e614 100644 --- a/bin/lang-check.js +++ b/bin/lang-check.js @@ -1,9 +1,9 @@ -import SimpleCliCommand from '../lib/SimpleCliCommand.js' +import CliCommand from '../lib/CliCommand.js' import fs from 'node:fs/promises' import { glob } from 'glob' import path from 'node:path' -export default class Langcheck extends SimpleCliCommand { +export default class Langcheck extends CliCommand { get config () { return { ...super.config, diff --git a/bin/mail-test.js b/bin/mail-test.js index 4adf31d..f366057 100644 --- a/bin/mail-test.js +++ b/bin/mail-test.js @@ -1,5 +1,5 @@ import CliCommand from '../lib/CliCommand.js' -import Utils from '../lib/Utils.js' +import internalApiRequest from '../lib/utils/internalApiRequest.js' export default class MailTest extends CliCommand { get config () { @@ -7,16 +7,14 @@ export default class MailTest extends CliCommand { ...super.config, description: 'Sends a test email', params: { email: 'Recipient email address for the test' }, - options: [['--v --verbose', 'Include extra debug messages']], - getReleaseData: false + options: [['--v --verbose', 'Include extra debug messages']] } } async runTask () { try { - await Utils.internalApiRequest('mailer/test', { email: this.options.email }) + await internalApiRequest('mailer/test', { email: this.options.email }) console.log('Email test successful') - process.exitCode = 0 } catch (e) { console.log(`Email test failed with error code ${e.code} (${e.statusCode}):`) console.log(`\n${e.message}`) diff --git a/bin/register-super.js b/bin/register-super.js index ed47588..efaae8f 100644 --- a/bin/register-super.js +++ b/bin/register-super.js @@ -1,26 +1,25 @@ import CliCommand from '../lib/CliCommand.js' -import Utils from '../lib/Utils.js' +import registerSuperUser from '../lib/utils/registerSuperUser.js' -export default class Install extends CliCommand { +export default class RegisterSuper extends CliCommand { get config () { return { ...super.config, description: 'Registers a super user account', + checkPrerequisites: true, options: [ ['-e --super-email ', 'The admin user email address'], ['--ignore-prereqs', 'Whether to skip the prerequisites check. Warning this could result in expected errors'], ['-p --pipe-passwd', 'Whether the admin password will be piped into the script'], ['--v --verbose', 'Include extra debug messages'] - ], - getReleaseData: false + ] } } async runTask () { try { - await Utils.registerSuperUser(this.options) + await registerSuperUser(this.options) console.log('Super user registered successfully.') - process.exitCode = 0 } catch (e) { console.log(`Super User registration failed with error code ${e.code} (${e.statusCode}):`) console.log(`\n${e.message}`) diff --git a/bin/release-notes.js b/bin/release-notes.js index ce971ff..fc7868e 100644 --- a/bin/release-notes.js +++ b/bin/release-notes.js @@ -1,10 +1,10 @@ import { readFileSync } from 'node:fs' import { join } from 'node:path' import semver from 'semver' -import SimpleCliCommand from '../lib/SimpleCliCommand.js' +import CliCommand from '../lib/CliCommand.js' import { compareVersions } from '../lib/versionCompare.js' -export default class ReleaseNotes extends SimpleCliCommand { +export default class ReleaseNotes extends CliCommand { get config () { return { ...super.config, diff --git a/bin/schema-check.js b/bin/schema-check.js index 84bf888..4472007 100644 --- a/bin/schema-check.js +++ b/bin/schema-check.js @@ -1,7 +1,7 @@ -import SimpleCliCommand from '../lib/SimpleCliCommand.js' +import CliCommand from '../lib/CliCommand.js' import checkSchemaForDuplicates from '../lib/utils/checkSchemaForDuplicates.js' -export default class Schemacheck extends SimpleCliCommand { +export default class Schemacheck extends CliCommand { get config () { return { ...super.config, diff --git a/bin/update.js b/bin/update.js index 7431643..dd00484 100644 --- a/bin/update.js +++ b/bin/update.js @@ -1,7 +1,7 @@ import CliCommand from '../lib/CliCommand.js' import DEFAULT_OPTIONS from '../lib/DEFAULT_OPTIONS.js' +import Installer from '../lib/Installer.js' import UiServer from '../lib/UiServer.js' -import Utils from '../lib/Utils.js' export default class Update extends CliCommand { get config () { @@ -9,6 +9,8 @@ export default class Update extends CliCommand { ...super.config, description: 'Updates the application in destination directory', params: { destination: 'The destination folder for the source code' }, + checkPrerequisites: true, + getReleaseData: true, options: [ ...DEFAULT_OPTIONS, ['-d --dry-run', 'Check for update without performing any update actions'], @@ -27,7 +29,8 @@ export default class Update extends CliCommand { .on('exit', e => this.cleanUp(e)) } if (!this.options.releaseData.releases.length) { - return this.cleanUp('No release data was retrievable.') + console.log('No updates available.') + return } const latestRelease = this.options.releaseData.releases[0] @@ -39,11 +42,13 @@ export default class Update extends CliCommand { if (this.options.dryRun) { return } - console.log(`Updating Adapt authoring tool in ${this.options.cwd}\n`) try { if (!this.options.tag) this.options.tag = await this.getReleaseInput() - await Utils.updateRepo(this.options) - this.cleanUp() + + console.log(`Updating Adapt authoring tool in ${this.options.cwd}\n`) + await new Installer(this.options).update() + + this.logSuccess('Update completed successfully!') } catch (e) { this.cleanUp(e) } diff --git a/bin/version-check.js b/bin/version-check.js index 8e1b046..5d45931 100644 --- a/bin/version-check.js +++ b/bin/version-check.js @@ -1,7 +1,7 @@ -import SimpleCliCommand from '../lib/SimpleCliCommand.js' +import CliCommand from '../lib/CliCommand.js' import { compareVersions } from '../lib/versionCompare.js' -export default class VersionCheck extends SimpleCliCommand { +export default class VersionCheck extends CliCommand { get config () { return { ...super.config, diff --git a/index.js b/index.js index 2f77341..47f4f6f 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,10 @@ #!/usr/bin/env node import fs from 'fs/promises' import path from 'path' +import { fileURLToPath } from 'url' import { Command, program } from 'commander' -import Utils from './lib/Utils.js' +import getCliRoot from './lib/utils/getCliRoot.js' +import loadPackage from './lib/utils/loadPackage.js' import CliCommand from './lib/CliCommand.js' const scriptsDir = new URL('bin', import.meta.url) @@ -42,9 +44,9 @@ function wrapParam (p) { return `${optional ? '[' : '<'}${name}${optional ? ']' : '>'}` } -async function run () { +export async function run () { try { - const { repository, version } = await Utils.loadPackage(Utils.getCliRoot()) + const { repository, version } = await loadPackage(getCliRoot()) const repoName = repository.toString().replace('github:', '') console.log(`\nRunning ${repoName}@${version}\n`) @@ -60,4 +62,6 @@ async function run () { } } -export default run() +if (process.argv[1] === fileURLToPath(import.meta.url)) { + run() +} diff --git a/lib/CliCommand.js b/lib/CliCommand.js index eb81cf7..d0de29e 100644 --- a/lib/CliCommand.js +++ b/lib/CliCommand.js @@ -1,22 +1,26 @@ -import { exec } from 'child_process' -import fs from 'fs/promises' import path from 'path' import prompts from 'prompts' -import Utils from './Utils.js' +import checkPrerequisites from './utils/checkPrerequisites.js' +import getInstalledVersion from './utils/getInstalledVersion.js' +import getReleases from './utils/getReleases.js' +import getStartCommands from './utils/getStartCommands.js' export default class CliCommand { get config () { return { - description: undefined, // String, A human-readable description of the command - options: [], // 2d array, e.g. [['--option', 'Option description ]] - params: {} // Object, e.g. { param: 'Param description' } + description: undefined, + options: [], + params: {}, + checkPrerequisites: false, + getReleaseData: false } } async run (...args) { try { - await this.setOptions(args) - await Utils.checkPrerequisites(this.options) + this.setOptions(args) + if (this.config.checkPrerequisites) await checkPrerequisites(this.options) + if (this.config.getReleaseData) this.options.releaseData = await this.getReleaseData() await this.runTask() } catch (e) { this.cleanUp(e) @@ -27,7 +31,7 @@ export default class CliCommand { throw new Error('Should be overridden in subclass') } - async setOptions (args) { + setOptions (args) { const paramKeys = Object.keys(this.config.params) const params = paramKeys.reduce((m, k, i) => Object.assign(m, { [k]: args[i] }), {}) const [opts, command] = args.slice(paramKeys.length) @@ -42,36 +46,13 @@ export default class CliCommand { action: command.name(), cwd: dest ? path.resolve(dest) : process.cwd() } - if (this.config.getReleaseData !== false) this.options.releaseData = await this.getReleaseData() - } - - async cloneRepo () { - const configPath = path.resolve(this.options.cwd, 'conf', `${process.env.NODE_ENV}.config.js`) - try { - this.configContents = await fs.readFile(configPath) - } catch (e) { - throw e.code === 'ENOENT' ? new Error(`Expected config file at '${configPath}'`) : e - } - // remove config because git clone won't work - await fs.rm(path.dirname(configPath), { recursive: true }) - await Utils.cloneRepo(this.options) - // reinstate config - await fs.mkdir(path.dirname(configPath)) - await fs.writeFile(configPath, this.configContents) - } - - async updateRepo () { - Utils.updateRepo(this.options) } async getReleaseData () { - let currentVersion - try { - currentVersion = (await Utils.exec('git symbolic-ref -q --short HEAD || git describe --tags --exact-match', this.options.cwd)).trim() - } catch (e) {} + const currentVersion = await getInstalledVersion(this.options.cwd) return { currentVersion, - releases: await Utils.getReleases({ ...this.options, currentVersion }) + releases: await getReleases({ ...this.options, currentVersion }) } } @@ -83,26 +64,31 @@ export default class CliCommand { choices: this.options.releaseData.releases.map(r => { return { title: r.bump ? `${r.name} (${r.bump})` : r.name, value: r } }) }]) + if (!release) { + console.log('\nGoodbye.') + this.cleanUp(new Error('User cancelled install')) + return + } + console.log(`!! SELECTED RELEASE: ${release.name} (${release.date instanceof Date && !isNaN(release.date) ? release.date.toISOString().split('T')[0] : release.published_at})`) if (release.bump) console.log(`!! UPDATE TYPE: ${release.bump}`) console.log(`\n${release.body}\n\n${'-'.repeat(80)}\n`) - if (release) { - let warning = '' - if (release.branch || release.draft || release.prerelease) { - warning = 'WARNING! YOU HAVE CHOSEN TO INSTALL A NON-STABLE VERSION WHICH IS NOT SUITABLE FOR PRODUCTION. PLEASE PROCEED WITH CAUTION.' - } else if (release.bump === 'major') { - warning = 'WARNING! This is a MAJOR version update which may include breaking changes. Please review the release notes carefully and ensure you have a backup before proceeding.' - } - const { confirmed } = await this.getInput([{ - type: 'confirm', - name: 'confirmed', - message: 'Would you like to continue?', - initial: false - }], warning) - console.log('\n') - if (confirmed) return release.tag_name + let warning = '' + if (release.branch || release.draft || release.prerelease) { + warning = 'WARNING! YOU HAVE CHOSEN TO INSTALL A NON-STABLE VERSION WHICH IS NOT SUITABLE FOR PRODUCTION. PLEASE PROCEED WITH CAUTION.' + } else if (release.bump === 'major') { + warning = 'WARNING! This is a MAJOR version update which may include breaking changes. Please review the release notes carefully and ensure you have a backup before proceeding.' } + const { confirmed } = await this.getInput([{ + type: 'confirm', + name: 'confirmed', + message: 'Would you like to continue?', + initial: false + }], warning) + console.log('\n') + if (confirmed) return release.tag_name + console.log('\nGoodbye.') this.cleanUp(new Error('User cancelled install')) } @@ -114,27 +100,21 @@ export default class CliCommand { return prompts(configs) } - async exec (command, cwd = process.cwd()) { - return new Promise((resolve, reject) => { - exec(command, { cwd }, (error, stdout, stderr) => error ? reject(new Error(stderr) || error) : resolve(stdout)) + logSuccess (message) { + const cmds = getStartCommands(this.options.cwd) + let msg = `\n${message} To start the app, run the following commands:\n\n` + Object.entries(cmds).forEach(([platform, cmd]) => { + msg += `${platform}:\n${cmd}\n\n` }) + console.log(msg) } - async cleanUp (error) { + cleanUp (error) { if (error) { console.log('\n') console.trace(error) console.log('\n') - } else { - const cmds = Utils.getStartCommands(this.options.cwd) - let msg = `\nGood news, the ${this.options.action} completed successfully! To start the app, run the following commands:\n\n` - Object.entries(cmds).forEach(([platform, cmd]) => { - msg += `${platform}:\n${cmd}\n\n` - }) - console.log(msg) } - console.log('Goodbye!') process.exitCode = error ? 1 : 0 - process.exit() } } diff --git a/lib/DEFAULT_OPTIONS.js b/lib/DEFAULT_OPTIONS.js index 5f10a5b..5bee4e9 100644 --- a/lib/DEFAULT_OPTIONS.js +++ b/lib/DEFAULT_OPTIONS.js @@ -1,10 +1,10 @@ export default [ - ['--branches --include-branches', 'Whether to include git branches THIS COULD BE DANGEROUS'], + ['--branches --include-branches', 'Whether to include branches THIS COULD BE DANGEROUS'], ['--dev --dev-mode', 'Developer installation NOT FOR PRODUCTION'], ['--drafts --include-drafts', 'Whether to include draft releases THIS COULD BE DANGEROUS'], ['--ignore-prereqs', 'Whether to skip the prerequisites check. Warning this could result in expected errors'], ['--prerelease --include-prereleases', 'Whether to include prereleases THIS COULD BE DANGEROUS'], ['--no-ui', 'Run in CLI-only mode'], - ['--tag ', 'A specific git tag to use'], + ['--tag ', 'A specific release tag to use'], ['--v --verbose', 'Include extra debug messages'] ] diff --git a/lib/Installer.js b/lib/Installer.js new file mode 100644 index 0000000..d3158cc --- /dev/null +++ b/lib/Installer.js @@ -0,0 +1,33 @@ +import downloadRelease from './utils/downloadRelease.js' +import getInstalledVersion, { writeInstalledVersion } from './utils/getInstalledVersion.js' +import swapInstall from './utils/swapInstall.js' + +export default class Installer { + constructor (options) { + this.options = options + } + + get stagingDir () { + return `${this.options.cwd}.aat-staging-${Date.now()}` + } + + async getInstalledVersion () { + return getInstalledVersion(this.options.cwd) + } + + async install () { + await downloadRelease({ tag: this.options.tag, targetDir: this.options.cwd }) + await writeInstalledVersion(this.options.cwd, this.options.tag) + } + + async update () { + const currentVersion = await this.getInstalledVersion() + if (!currentVersion) { + throw new Error(`No existing install found in ${this.options.cwd}`) + } + const stagingDir = this.stagingDir + await downloadRelease({ tag: this.options.tag, targetDir: stagingDir }) + await swapInstall({ stagingDir, targetDir: this.options.cwd, version: currentVersion }) + await writeInstalledVersion(this.options.cwd, this.options.tag) + } +} diff --git a/lib/SimpleCliCommand.js b/lib/SimpleCliCommand.js deleted file mode 100644 index 37b2218..0000000 --- a/lib/SimpleCliCommand.js +++ /dev/null @@ -1,11 +0,0 @@ -import CliCommand from './CliCommand.js' - -export default class SimpleCliCommand extends CliCommand { - async run (...args) { - const paramKeys = Object.keys(this.config.params) - const params = paramKeys.reduce((m, k, i) => Object.assign(m, { [k]: args[i] }), {}) - const [opts, command] = args.slice(paramKeys.length) - this.options = { ...opts, ...params, action: command.name() } - await this.runTask() - } -} diff --git a/lib/UiServer.js b/lib/UiServer.js index f27d330..8fe0e0c 100644 --- a/lib/UiServer.js +++ b/lib/UiServer.js @@ -5,11 +5,18 @@ import fs from 'fs/promises' import http from 'http' import { randomBytes } from 'crypto' import { spawn } from 'child_process' -import Utils from './Utils.js' +import Installer from './Installer.js' +import getAppDependencies from './utils/getAppDependencies.js' +import getReleases from './utils/getReleases.js' +import getSchemas from './utils/getSchemas.js' +import getStartCommands from './utils/getStartCommands.js' +import installLocalModules from './utils/installLocalModules.js' +import parseBody from './utils/parseBody.js' +import parseQuery from './utils/parseQuery.js' +import registerSuperUser from './utils/registerSuperUser.js' +import saveConfig from './utils/saveConfig.js' +import startApp from './utils/startApp.js' -/** - * Builder for the web app - */ export default class UiServer extends EventEmitter { constructor (options) { super() @@ -18,8 +25,9 @@ export default class UiServer extends EventEmitter { this.fileRoot = fileURLToPath(new URL('../public', import.meta.url).href) this.port = 8080 this.options = options + this.installer = new Installer(options) - if (this.options.action === 'install') { // install-specific endpoints + if (this.options.action === 'install') { this.get('/schemas/config', this.schemasHandler.bind(this)) this.get('/schemas/user', this.schemasHandler.bind(this)) this.post('/download', this.downloadHandler.bind(this)) @@ -28,14 +36,12 @@ export default class UiServer extends EventEmitter { this.post('/registeruser', this.registerUserHandler.bind(this)) this.post('/save', this.saveConfigHandler.bind(this)) this.post('/start', this.startAppHandler.bind(this)) - this.get('/checkpoint', this.getCheckpointHandler.bind(this)) - this.post('/checkpoint', this.saveCheckpointHandler.bind(this)) } if (this.options.devMode) { this.get('/modules', this.getModulesHandler.bind(this)) this.post('/installmodules', this.installModulesHandler.bind(this)) } - if (this.options.action === 'update') { // update-specific endpoints + if (this.options.action === 'update') { this.post('/update', this.updateHandler.bind(this)) } this.get('/commands', this.commandHandler.bind(this)) @@ -86,8 +92,8 @@ export default class UiServer extends EventEmitter { if (serveSuccess) { return } - req.query = Utils.parseQuery(req) - req.body = await Utils.parseBody(req) + req.query = parseQuery(req) + req.body = await parseBody(req) const handler = this._handlers[req.method.toLowerCase()][req.url] if (handler) { @@ -101,7 +107,7 @@ export default class UiServer extends EventEmitter { } async tryStaticServe (req, res) { - try { // serve static file + try { const isIndex = req.url === '/' if (isIndex) req.url = '/index.html' let contents = (await fs.readFile(`${this.fileRoot}${req.url}`)) @@ -132,47 +138,43 @@ export default class UiServer extends EventEmitter { async schemasHandler (req, res) { if (!this.schemas) { - this.schemas = await Utils.getSchemas(this.options.cwd) + this.schemas = await getSchemas(this.options.cwd) } res.json(this.schemas[req.url.replace('/schemas/', '')]) } async registerUserHandler (req, res) { try { - await Utils.registerSuperUser({ ...this.options, superEmail: req.body.email, superPassword: req.body.password }) + await registerSuperUser({ ...this.options, superEmail: req.body.email, superPassword: req.body.password }) res.send(undefined, 201) } catch (e) { - const app = await Utils.startApp(this.options) + const app = await startApp(this.options) res.send(e.constructor.name === 'AdaptError' ? app.lang.translate('en', e) : e.message, e.statusCode) } } async saveConfigHandler (req, res) { - await Utils.saveConfig(this.options.cwd, req.body) + await saveConfig(this.options.cwd, req.body) res.json({ rootDir: this.options.cwd }) } async downloadHandler (req, res) { let tag = req.query.tag if (!tag) { - const [latestRelease] = await Utils.getReleases(this.options) + const [latestRelease] = await getReleases(this.options) if (!latestRelease) { throw new Error('No releases found') } tag = latestRelease.name } - try { - await Utils.cloneRepo({ ...this.options, tag }) - } catch (e) { - if (e.code !== 'GITCLONEEEXIST' || !this.options.resumeStep) throw e - console.log('Repository already exists from previous install, reinstalling dependencies') - await Utils.exec('npm ci', this.options.cwd) - } + this.installer.options.tag = tag + await this.installer.install() res.end() } async prereqHandler (req, res) { - await Utils.checkPrerequisites(this.options) + const checkPrerequisites = (await import('./utils/checkPrerequisites.js')).default + await checkPrerequisites(this.options) res.send() } @@ -187,7 +189,7 @@ export default class UiServer extends EventEmitter { })) if (Object.values(data).length && Object.values(data).some(Boolean)) return data } - const { config: schemas } = await Utils.getSchemas(this.options.cwd) + const { config: schemas } = await getSchemas(this.options.cwd) const data = {} await Promise.all(Object.entries(schemas).map(async ([id, { schema }]) => { data[id] = await setSecretsRecursive(schema) @@ -196,7 +198,7 @@ export default class UiServer extends EventEmitter { } async startAppHandler (req, res) { - const app = await Utils.startApp(this.options) + const app = await startApp(this.options) const ui = await app.waitForModule('ui') ui.postBuildHook.tap(() => res.send()) } @@ -206,40 +208,26 @@ export default class UiServer extends EventEmitter { } async getModulesHandler (req, res) { - res.json((await Utils.getAppDependencies(this.options.cwd)).adapt) + res.json((await getAppDependencies(this.options.cwd)).adapt) } async installModulesHandler (req, res) { - await Utils.installLocalModules({ ...this.options, modules: req.body }) + await installLocalModules({ ...this.options, modules: req.body }) res.send() } async updateHandler (req, res) { - await Utils.updateRepo({ ...this.options, tag: req.query.version }) + this.installer.options.tag = req.query.version + await this.installer.update() res.end() } async commandHandler (req, res) { - res.json(Utils.getStartCommands(this.options.cwd)) + res.json(getStartCommands(this.options.cwd)) } async exitHandler (req, res) { - await Utils.clearInstallState(this.options.cwd) res.end() this.onExit(typeof req.body === 'string' ? new Error(req.body) : undefined) } - - async getCheckpointHandler (req, res) { - const state = await Utils.getInstallState(this.options.cwd) - if (state) { - res.json(state) - } else { - res.send(undefined, 404) - } - } - - async saveCheckpointHandler (req, res) { - await Utils.saveInstallState(this.options.cwd, req.body) - res.send() - } } diff --git a/lib/Utils.js b/lib/Utils.js deleted file mode 100644 index 85ad5fd..0000000 --- a/lib/Utils.js +++ /dev/null @@ -1,53 +0,0 @@ -import buildPackageIndex from './utils/buildPackageIndex.js' -import checkPrerequisites from './utils/checkPrerequisites.js' -import cloneRepo from './utils/cloneRepo.js' -import collectJsFiles from './utils/collectJsFiles.js' -import exec from './utils/exec.js' -import getAppDependencies from './utils/getAppDependencies.js' -import getCliRoot from './utils/getCliRoot.js' -import getReleases from './utils/getReleases.js' -import getModuleDirs from './utils/getModuleDirs.js' -import getSchemas from './utils/getSchemas.js' -import getStartCommands from './utils/getStartCommands.js' -import githubRequest from './utils/githubRequest.js' -import importCore from './utils/importCore.js' -import { getInstallState, saveInstallState, clearInstallState } from './utils/installState.js' -import installLocalModules from './utils/installLocalModules.js' -import isModule from './utils/isModule.js' -import loadJson from './utils/loadJson.js' -import loadPackage from './utils/loadPackage.js' -import startApp from './utils/startApp.js' -import parseBody from './utils/parseBody.js' -import parseQuery from './utils/parseQuery.js' -import registerSuperUser from './utils/registerSuperUser.js' -import saveConfig from './utils/saveConfig.js' -import updateRepo from './utils/updateRepo.js' - -export default { - buildPackageIndex, - checkPrerequisites, - clearInstallState, - cloneRepo, - collectJsFiles, - exec, - getAppDependencies, - getCliRoot, - getInstallState, - getModuleDirs, - getReleases, - getSchemas, - getStartCommands, - githubRequest, - importCore, - installLocalModules, - isModule, - loadJson, - loadPackage, - parseBody, - parseQuery, - registerSuperUser, - saveConfig, - saveInstallState, - startApp, - updateRepo -} diff --git a/lib/utils/cloneRepo.js b/lib/utils/cloneRepo.js deleted file mode 100644 index f3d7cce..0000000 --- a/lib/utils/cloneRepo.js +++ /dev/null @@ -1,19 +0,0 @@ -import exec from './exec.js' - -const GITHUB_ORG_URL = 'https://github.com/adapt-security' -const GITHUB_REPO = 'adapt-authoring' - -export default async function cloneRepo (options) { - const url = `${GITHUB_ORG_URL}/${options.repo || GITHUB_REPO}.git` - const tag = options.tag || 'master' - console.log(`Cloning ${url}#${tag} into ${options.cwd}`) - try { - await exec(`git clone --branch ${tag} ${url} ${options.cwd}`) - } catch (e) { - const error = new Error(`Failed to clone git repository, ${e.message}`) - error.code = 'GITCLONEEEXIST' - throw error - } - console.log('Installing npm dependencies') - await exec(`npm ${options.cleanInstall === false ? 'install' : 'ci'}`, options.cwd) -} diff --git a/lib/utils/downloadRelease.js b/lib/utils/downloadRelease.js new file mode 100644 index 0000000..17d89c0 --- /dev/null +++ b/lib/utils/downloadRelease.js @@ -0,0 +1,27 @@ +import { pipeline } from 'stream/promises' +import { createGunzip } from 'zlib' +import fs from 'fs/promises' +import { Unpack } from 'tar' +import exec from './exec.js' +import githubHeaders from './githubHeaders.js' + +const GITHUB_ORG = 'adapt-security' +const DEFAULT_REPO = 'adapt-authoring' + +export default async function downloadRelease ({ tag, targetDir, repo = DEFAULT_REPO, cleanInstall = true }) { + await fs.mkdir(targetDir, { recursive: true }) + + console.log(`Downloading ${repo}@${tag}`) + const response = await fetch(`https://api.github.com/repos/${GITHUB_ORG}/${repo}/tarball/${tag}`, { headers: githubHeaders() }) + if (!response.ok) { + throw new Error(`Failed to download release ${tag}: ${response.status} ${response.statusText}`) + } + console.log('Extracting') + await pipeline( + response.body, + createGunzip(), + new Unpack({ cwd: targetDir, strip: 1 }) + ) + console.log('Installing npm dependencies') + await exec(`npm ${cleanInstall ? 'ci' : 'install'}`, targetDir) +} diff --git a/lib/utils/getInstalledVersion.js b/lib/utils/getInstalledVersion.js new file mode 100644 index 0000000..8827925 --- /dev/null +++ b/lib/utils/getInstalledVersion.js @@ -0,0 +1,16 @@ +import fs from 'fs/promises' +import path from 'path' + +const VERSION_FILE = path.join('conf', '.version') + +export default async function getInstalledVersion (cwd) { + try { + return (await fs.readFile(path.join(cwd, VERSION_FILE), 'utf8')).trim() + } catch (e) { + return null + } +} + +export async function writeInstalledVersion (cwd, version) { + await fs.writeFile(path.join(cwd, VERSION_FILE), version) +} diff --git a/lib/utils/getReleases.js b/lib/utils/getReleases.js index 283dbaa..e64237d 100644 --- a/lib/utils/getReleases.js +++ b/lib/utils/getReleases.js @@ -1,53 +1,41 @@ -import exec from './exec.js' -import githubRequest from './githubRequest.js' -import semver from 'semver' -import { normalizeBump } from '../versionCompare.js' - -export default async function getReleases (options) { - let currentVersionDate - try { - currentVersionDate = new Date(await exec('git log -1 --format=%cd', options.cwd)) - } catch (e) {} - const releases = (await githubRequest('releases?per_page=10')) - - if (options.includeBranches) { - await Promise.all((await githubRequest('branches')).map(async b => { - const { commit } = await githubRequest(b.commit.url.slice(b.commit.url.indexOf('commits/'))) - releases.push({ - name: `${b.name} (branch)`, - tag_name: b.name, - published_at: commit.author.date, - branch: true - }) - })) - } - return releases - .map(r => { - const diff = (semver.valid(options.currentVersion) && semver.valid(r.tag_name)) - ? semver.diff(options.currentVersion, r.tag_name) - : null - const bump = diff ? normalizeBump(diff) : null - return Object.assign(r, { - bump, - name: `${r.name}${r.draft ? ' (draft)' : r.prerelease ? ' (prerelease)' : ''}`, - date: new Date(r.published_at) - }) - }) - .filter(r => { - if (options.patchOnly && r.bump !== null && r.bump !== 'patch') return false - if (options.minorOnly && r.bump !== null && r.bump !== 'patch' && r.bump !== 'minor') return false - if ((r.tag_name === options.currentVersion) || (r.prerelease && !options.includePrereleases) || (r.draft && !options.includeDrafts)) { - return false - } - const noCurrent = !options.currentVersion - const semverNewer = (semver.valid(options.currentVersion) && semver.valid(r.tag_name) && semver.gt(r.tag_name, options.currentVersion)) ?? false - const gitNewer = r.date > currentVersionDate - return noCurrent || semverNewer || gitNewer - }) - .filter(r => { - if (options.patchOnly && r.bump !== null && r.bump !== 'patch') return false - if (options.minorOnly && r.bump !== null && r.bump === 'major') return false - return true - }) - .sort((a, b) => a.date < b.date ? 1 : -1) -} +import githubRequest from './githubRequest.js' +import semver from 'semver' +import { normalizeBump } from '../versionCompare.js' + +export default async function getReleases (options) { + const releases = (await githubRequest('releases?per_page=10')) + + if (options.includeBranches) { + await Promise.all((await githubRequest('branches')).map(async b => { + const { commit } = await githubRequest(b.commit.url.slice(b.commit.url.indexOf('commits/'))) + releases.push({ + name: `${b.name} (branch)`, + tag_name: b.name, + published_at: commit.author.date, + branch: true + }) + })) + } + return releases + .map(r => { + const diff = (semver.valid(options.currentVersion) && semver.valid(r.tag_name)) + ? semver.diff(options.currentVersion, r.tag_name) + : null + const bump = diff ? normalizeBump(diff) : null + return Object.assign(r, { + bump, + name: `${r.name}${r.draft ? ' (draft)' : r.prerelease ? ' (prerelease)' : ''}`, + date: new Date(r.published_at) + }) + }) + .filter(r => { + if (r.tag_name === options.currentVersion) return false + if (r.prerelease && !options.includePrereleases) return false + if (r.draft && !options.includeDrafts) return false + if (options.patchOnly && r.bump !== null && r.bump !== 'patch') return false + if (options.minorOnly && r.bump !== null && r.bump === 'major') return false + if (!options.currentVersion) return true + return (semver.valid(options.currentVersion) && semver.valid(r.tag_name) && semver.gt(r.tag_name, options.currentVersion)) ?? false + }) + .sort((a, b) => a.date < b.date ? 1 : -1) +} diff --git a/lib/utils/githubHeaders.js b/lib/utils/githubHeaders.js new file mode 100644 index 0000000..560516d --- /dev/null +++ b/lib/utils/githubHeaders.js @@ -0,0 +1,8 @@ +export default function githubHeaders () { + const headers = { Accept: 'application/vnd.github+json', 'User-Agent': 'at-utils' } + const { GITHUB_USER, GITHUB_TOKEN } = process.env + if (GITHUB_USER && GITHUB_TOKEN) { + headers.Authorization = `Basic ${Buffer.from(`${GITHUB_USER}:${GITHUB_TOKEN}`).toString('base64')}` + } + return headers +} diff --git a/lib/utils/githubRequest.js b/lib/utils/githubRequest.js index b3ecabb..3eb6e3f 100644 --- a/lib/utils/githubRequest.js +++ b/lib/utils/githubRequest.js @@ -1,25 +1,22 @@ -export default async function githubRequest (endpoint, opts = {}) { - const { GITHUB_USER, GITHUB_TOKEN } = process.env - - if (GITHUB_USER && GITHUB_TOKEN) { - const authHash = Buffer.from(`${GITHUB_USER}:${GITHUB_TOKEN}`).toString('base64') - opts.headers = { Authorization: `Basic ${authHash}` } - } - const response = await fetch(`https://api.github.com/repos/adapt-security/adapt-authoring/${endpoint}`, opts) - if (response.status > 299) { - const isRateLimit = response.status === 429 || - (response.status === 403 && response.headers.get('X-RateLimit-Remaining') === '0') - if (isRateLimit) { - const resetTime = response.headers.get('X-RateLimit-Reset') - const resetMsg = resetTime ? ` Rate limit resets at ${new Date(resetTime * 1000).toUTCString()}.` : '' // resetTime is Unix epoch (seconds) - throw new Error(`GitHub API rate limit exceeded.${resetMsg} You can set the GITHUB_USER and GITHUB_TOKEN environment variables to increase your rate limit.`) - } - let errorMessage = response.statusText - try { - const body = await response.json() - if (body.message) errorMessage = body.message - } catch (e) {} // body may not be valid JSON; fall back to statusText - throw new Error(errorMessage) - } - if (response.status !== 204) return response.json() -} +import githubHeaders from './githubHeaders.js' + +export default async function githubRequest (endpoint, opts = {}) { + opts.headers = { ...githubHeaders(), ...opts.headers } + const response = await fetch(`https://api.github.com/repos/adapt-security/adapt-authoring/${endpoint}`, opts) + if (response.status > 299) { + const isRateLimit = response.status === 429 || + (response.status === 403 && response.headers.get('X-RateLimit-Remaining') === '0') + if (isRateLimit) { + const resetTime = response.headers.get('X-RateLimit-Reset') + const resetMsg = resetTime ? ` Rate limit resets at ${new Date(resetTime * 1000).toUTCString()}.` : '' // resetTime is Unix epoch (seconds) + throw new Error(`GitHub API rate limit exceeded.${resetMsg} You can set the GITHUB_USER and GITHUB_TOKEN environment variables to increase your rate limit.`) + } + let errorMessage = response.statusText + try { + const body = await response.json() + if (body.message) errorMessage = body.message + } catch (e) {} // body may not be valid JSON; fall back to statusText + throw new Error(errorMessage) + } + if (response.status !== 204) return response.json() +} diff --git a/lib/utils/installLocalModules.js b/lib/utils/installLocalModules.js index 6d44df1..c4bb289 100644 --- a/lib/utils/installLocalModules.js +++ b/lib/utils/installLocalModules.js @@ -1,9 +1,9 @@ -import cloneRepo from './cloneRepo.js' -import exec from './exec.js' -import path from 'path' - -export default async function installLocalModules (options) { - const dir = path.join(options.cwd, 'local_adapt_modules') - await Promise.all(options.modules.map(m => cloneRepo({ repo: m, cwd: path.join(dir, m), cleanInstall: false }))) - return exec('npm install', options.cwd) // need to run another npm install to pull in the local repos +import downloadRelease from './downloadRelease.js' +import exec from './exec.js' +import path from 'path' + +export default async function installLocalModules (options) { + const dir = path.join(options.cwd, 'local_adapt_modules') + await Promise.all(options.modules.map(m => downloadRelease({ repo: m, tag: 'master', targetDir: path.join(dir, m), cleanInstall: false }))) + return exec('npm install', options.cwd) // need to run another npm install to pull in the local repos } diff --git a/lib/utils/installState.js b/lib/utils/installState.js deleted file mode 100644 index f3e0d3a..0000000 --- a/lib/utils/installState.js +++ /dev/null @@ -1,24 +0,0 @@ -import fs from 'fs/promises' -import path from 'path' - -function getStatePath (cwd) { - return path.resolve(cwd, '.install-state.json') -} - -export async function getInstallState (cwd) { - try { - return JSON.parse(await fs.readFile(getStatePath(cwd), 'utf8')) - } catch (e) { - return null - } -} - -export async function saveInstallState (cwd, state) { - await fs.writeFile(getStatePath(cwd), JSON.stringify({ ...state, timestamp: new Date().toISOString() })) -} - -export async function clearInstallState (cwd) { - try { - await fs.unlink(getStatePath(cwd)) - } catch (e) {} -} diff --git a/lib/utils/internalApiRequest.js b/lib/utils/internalApiRequest.js new file mode 100644 index 0000000..e3ac98f --- /dev/null +++ b/lib/utils/internalApiRequest.js @@ -0,0 +1,23 @@ +import { pathToFileURL } from 'url' +import path from 'path' + +export default async function internalApiRequest (endpoint, data, opts = {}) { + const options = { + method: opts.method ?? 'POST', + headers: opts.headers ?? { 'Content-Type': 'application/json' }, + body: data ? JSON.stringify(data) : undefined + } + const config = (await import(pathToFileURL(path.join(opts.cwd ?? process.cwd(), 'conf', `${process.env.NODE_ENV}.config.js`)))).default + const { host, port } = config['adapt-authoring-server'] + const response = await fetch(`http://${host}:${port}/api/${endpoint}`, options) + if (response.status === 204) { + return + } + if (response.status > 299) { + const responseData = await response.json() + const e = new Error(responseData.message) + e.code = responseData.code + e.statusCode = response.status + throw e + } +} diff --git a/lib/utils/registerSuperUser.js b/lib/utils/registerSuperUser.js index c3444de..f2b6ec0 100644 --- a/lib/utils/registerSuperUser.js +++ b/lib/utils/registerSuperUser.js @@ -1,78 +1,56 @@ -import { createInterface } from 'readline' -import { pathToFileURL } from 'url' -import path from 'path' -import prompts from 'prompts' -import startApp from './startApp.js' - -export default async function registerSuperUser (options = {}) { - try { - await internalApiRequest('', undefined, { ...options, method: 'GET' }) - } catch (e) { - if ((e.code ?? e.cause?.code) !== 'ECONNREFUSED') throw e - await startApp(options) - } - let email = options.superEmail - let password = options.pipePasswd ? await getPipedPassword() : options.superPassword - let success = false - while (!success) { - try { - if (!email) { - const { emailInput } = await await prompts([{ - type: 'text', - name: 'emailInput', - message: 'Enter an email address to be used as a login for the Super User account' - }]) - email = emailInput - } - if (!password) { - const { passwordInput1, passwordInput2 } = await prompts([{ - type: 'password', - name: 'passwordInput1', - message: 'Enter a password for the Super User account' - }, { - type: 'password', - name: 'passwordInput2', - message: 'Please type the password again to confirm' - }]) - if (passwordInput1 !== passwordInput2) { - console.log('Passwords don\'t match. Please try again') - continue - } - password = passwordInput1 - } - await internalApiRequest('auth/local/registersuper', { email, password }, options) - success = true - } catch (e) { - if (e.code !== 'VALIDATION_FAILED') throw e // only loop if it's a validation error - console.log(`\nERROR: Failed to register super user, ${e.data.errors}\n`) - } - } -} - -function getPipedPassword () { - return new Promise(resolve => { - createInterface({ input: process.stdin, output: process.stdout, terminal: false }) - .on('line', s => resolve(s)) - }) -} - -async function internalApiRequest (endpoint, data, opts = {}) { - const options = { - method: opts.method ?? 'POST', - headers: opts.headers ?? { 'Content-Type': 'application/json' }, - body: data ? JSON.stringify(data) : undefined - } - const config = (await import(pathToFileURL(path.join(opts.cwd ?? process.cwd(), 'conf', `${process.env.NODE_ENV}.config.js`)))).default - const { host, port } = config['adapt-authoring-server'] - const response = await fetch(`http://${host}:${port}/api/${endpoint}`, options) - if (response.status === 204) { - return - } - if (response.status > 299) { - const responseData = await response.json() - const e = new Error(responseData.message) - e.code = responseData.code - e.statusCode = response.status - throw e - } -} +import { createInterface } from 'readline' +import prompts from 'prompts' +import internalApiRequest from './internalApiRequest.js' +import startApp from './startApp.js' + +export default async function registerSuperUser (options = {}) { + try { + await internalApiRequest('', undefined, { ...options, method: 'GET' }) + } catch (e) { + if ((e.code ?? e.cause?.code) !== 'ECONNREFUSED') throw e + await startApp(options) + } + let email = options.superEmail + let password = options.pipePasswd ? await getPipedPassword() : options.superPassword + let success = false + while (!success) { + try { + if (!email) { + const { emailInput } = await prompts([{ + type: 'text', + name: 'emailInput', + message: 'Enter an email address to be used as a login for the Super User account' + }]) + email = emailInput + } + if (!password) { + const { passwordInput1, passwordInput2 } = await prompts([{ + type: 'password', + name: 'passwordInput1', + message: 'Enter a password for the Super User account' + }, { + type: 'password', + name: 'passwordInput2', + message: 'Please type the password again to confirm' + }]) + if (passwordInput1 !== passwordInput2) { + console.log('Passwords don\'t match. Please try again') + continue + } + password = passwordInput1 + } + await internalApiRequest('auth/local/registersuper', { email, password }, options) + success = true + } catch (e) { + if (e.code !== 'VALIDATION_FAILED') throw e // only loop if it's a validation error + console.log(`\nERROR: Failed to register super user, ${e.data.errors}\n`) + } + } +} + +function getPipedPassword () { + return new Promise(resolve => { + createInterface({ input: process.stdin, output: process.stdout, terminal: false }) + .on('line', s => resolve(s)) + }) +} diff --git a/lib/utils/swapInstall.js b/lib/utils/swapInstall.js new file mode 100644 index 0000000..f8336e0 --- /dev/null +++ b/lib/utils/swapInstall.js @@ -0,0 +1,18 @@ +import fs from 'fs/promises' +import path from 'path' + +export default async function swapInstall ({ stagingDir, targetDir, version }) { + const confDir = path.join(targetDir, 'conf') + const stagingConfDir = path.join(stagingDir, 'conf') + + // copy conf/ from current install into staging + await fs.cp(confDir, stagingConfDir, { recursive: true }) + + // rename current to backup, staging to target + const backupDir = `${targetDir}.backup-${version}` + await fs.rename(targetDir, backupDir) + await fs.rename(stagingDir, targetDir) + + // clean up backup + await fs.rm(backupDir, { recursive: true, force: true }) +} diff --git a/lib/utils/updateRepo.js b/lib/utils/updateRepo.js deleted file mode 100644 index b24a7b2..0000000 --- a/lib/utils/updateRepo.js +++ /dev/null @@ -1,12 +0,0 @@ -import exec from './exec.js' -import fs from 'fs/promises' - -export default async function updateRepo (options) { - console.log(`Checking out ${options.tag} in ${options.cwd}`) - await exec('git fetch --all --tags', options.cwd) - await exec('git reset --hard', options.cwd) - await exec(`git checkout ${options.tag}`, options.cwd) - await fs.rm(`${options.cwd}/node_modules`, { recursive: true }) - console.log('Installing npm dependencies') - await exec('npm ci', options.cwd) -} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..d691e80 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,8936 @@ +{ + "name": "@adapt-security/at-utils", + "version": "0.21.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@adapt-security/at-utils", + "version": "0.21.1", + "license": "MIT", + "dependencies": { + "commander": "^14.0.3", + "glob": "^13.0.0", + "prompts": "^2.4.2", + "semver": "^7.7.4", + "tar": "^7.5.13" + }, + "bin": { + "at-utils": "index.js" + }, + "devDependencies": { + "@adaptlearning/semantic-release-config": "^1.0.0", + "standard": "^17.1.0" + } + }, + "node_modules/@actions/core": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@actions/exec": "^3.0.0", + "@actions/http-client": "^4.0.0" + } + }, + "node_modules/@actions/exec": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@actions/io": "^3.0.2" + } + }, + "node_modules/@actions/http-client": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "tunnel": "^0.0.6", + "undici": "^6.23.0" + } + }, + "node_modules/@actions/http-client/node_modules/undici": { + "version": "6.23.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/@actions/io": { + "version": "3.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@adaptlearning/semantic-release-config": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@adaptlearning/semantic-release-config/-/semantic-release-config-1.0.2.tgz", + "integrity": "sha512-fEXayBcmzg6+/Y05ygvJ0tlHALmtn++XHDqRpx9UbYWtgqolU6+9pA3UUAwyDVARggA/J99p1/3WrnE34AXqdQ==", + "dev": true, + "license": "GPL-3.0", + "dependencies": { + "@semantic-release/git": "^10.0.1", + "conventional-changelog-eslint": "^6.0.0", + "semantic-release": "^25.0.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "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/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@octokit/auth-token": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/core": { + "version": "7.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^6.0.0", + "@octokit/graphql": "^9.0.3", + "@octokit/request": "^10.0.6", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "before-after-hook": "^4.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/endpoint": { + "version": "11.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/graphql": { + "version": "9.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request": "^10.0.6", + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "27.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "14.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-retry": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=7" + } + }, + "node_modules/@octokit/plugin-throttling": { + "version": "11.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": "^7.0.0" + } + }, + "node_modules/@octokit/request": { + "version": "10.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^11.0.3", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "fast-content-type-parse": "^3.0.0", + "json-with-bigint": "^3.5.3", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/request-error": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/types": { + "version": "16.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^27.0.0" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "dev": true, + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@semantic-release/commit-analyzer": { + "version": "13.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-changelog-angular": "^8.0.0", + "conventional-changelog-writer": "^8.0.0", + "conventional-commits-filter": "^5.0.0", + "conventional-commits-parser": "^6.0.0", + "debug": "^4.0.0", + "import-from-esm": "^2.0.0", + "lodash-es": "^4.17.21", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/error": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@semantic-release/git": { + "version": "10.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@semantic-release/error": "^3.0.0", + "aggregate-error": "^3.0.0", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "execa": "^5.0.0", + "lodash": "^4.17.4", + "micromatch": "^4.0.0", + "p-reduce": "^2.0.0" + }, + "engines": { + "node": ">=14.17" + }, + "peerDependencies": { + "semantic-release": ">=18.0.0" + } + }, + "node_modules/@semantic-release/github": { + "version": "12.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/core": "^7.0.0", + "@octokit/plugin-paginate-rest": "^14.0.0", + "@octokit/plugin-retry": "^8.0.0", + "@octokit/plugin-throttling": "^11.0.0", + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "debug": "^4.3.4", + "dir-glob": "^3.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "issue-parser": "^7.0.0", + "lodash-es": "^4.17.21", + "mime": "^4.0.0", + "p-filter": "^4.0.0", + "tinyglobby": "^0.2.14", + "undici": "^7.0.0", + "url-join": "^5.0.0" + }, + "engines": { + "node": "^22.14.0 || >= 24.10.0" + }, + "peerDependencies": { + "semantic-release": ">=24.1.0" + } + }, + "node_modules/@semantic-release/github/node_modules/@semantic-release/error": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@semantic-release/github/node_modules/aggregate-error": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/github/node_modules/clean-stack": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/github/node_modules/escape-string-regexp": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/github/node_modules/indent-string": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm": { + "version": "13.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@actions/core": "^3.0.0", + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "env-ci": "^11.2.0", + "execa": "^9.0.0", + "fs-extra": "^11.0.0", + "lodash-es": "^4.17.21", + "nerf-dart": "^1.0.0", + "normalize-url": "^9.0.0", + "npm": "^11.6.2", + "rc": "^1.2.8", + "read-pkg": "^10.0.0", + "registry-auth-token": "^5.0.0", + "semver": "^7.1.2", + "tempy": "^3.0.0" + }, + "engines": { + "node": "^22.14.0 || >= 24.10.0" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/@semantic-release/error": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@semantic-release/npm/node_modules/aggregate-error": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/clean-stack": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/escape-string-regexp": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/execa": { + "version": "9.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@semantic-release/npm/node_modules/get-stream": { + "version": "9.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/human-signals": { + "version": "8.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/indent-string": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/is-stream": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/npm-run-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/path-key": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@semantic-release/npm/node_modules/strip-final-newline": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/unicorn-magic": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator": { + "version": "14.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-changelog-angular": "^8.0.0", + "conventional-changelog-writer": "^8.0.0", + "conventional-commits-filter": "^5.0.0", + "conventional-commits-parser": "^6.0.0", + "debug": "^4.0.0", + "get-stream": "^7.0.0", + "import-from-esm": "^2.0.0", + "into-stream": "^7.0.0", + "lodash-es": "^4.17.21", + "read-package-up": "^11.0.0" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/get-stream": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/hosted-git-info": { + "version": "7.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/lru-cache": { + "version": "10.4.3", + "dev": true, + "license": "ISC" + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/normalize-package-data": { + "version": "6.0.2", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/parse-json": { + "version": "8.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/read-package-up": { + "version": "11.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/read-pkg": { + "version": "9.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/type-fest": { + "version": "4.41.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/unicorn-magic": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@simple-libs/stream-utils": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "dev": true, + "license": "ISC" + }, + "node_modules/acorn": { + "version": "8.16.0", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "dev": true, + "license": "MIT", + "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/ansi-escapes": { + "version": "7.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/argv-formatter": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-ify": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/array-includes": { + "version": "3.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/before-after-hook": { + "version": "4.0.0", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/bottleneck": { + "version": "2.19.5", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/builtins": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "dev": true, + "license": "ISC", + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/cli-highlight/node_modules/cliui": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/wrap-ansi": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "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/cli-highlight/node_modules/yargs": { + "version": "16.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-highlight/node_modules/yargs-parser": { + "version": "20.2.9", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cliui": { + "version": "9.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "10.6.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "14.0.3", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/compare-func": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "8.3.0", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-changelog-eslint": { + "version": "6.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "8.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^1.2.0", + "conventional-commits-filter": "^5.0.0", + "handlebars": "^4.7.7", + "meow": "^13.0.0", + "semver": "^7.5.2" + }, + "bin": { + "conventional-changelog-writer": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-commits-filter": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-commits-parser": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^1.2.0", + "meow": "^13.0.0" + }, + "bin": { + "conventional-commits-parser": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/convert-hrtime": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "9.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/emojilib": { + "version": "2.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/env-ci": { + "version": "11.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^8.0.0", + "java-properties": "^1.0.2" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, + "node_modules/env-ci/node_modules/execa": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/env-ci/node_modules/get-stream": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/human-signals": { + "version": "5.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/env-ci/node_modules/is-stream": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/mimic-fn": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/npm-run-path": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/onetime": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/path-key": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/env-ci/node_modules/strip-final-newline": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.1", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@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-config-standard": { + "version": "17.1.0", + "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" + } + ], + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-promise": "^6.0.0" + } + }, + "node_modules/eslint-config-standard-jsx": { + "version": "11.0.0", + "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" + } + ], + "license": "MIT", + "peerDependencies": { + "eslint": "^8.8.0", + "eslint-plugin-react": "^7.28.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-es": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-es/node_modules/eslint-utils": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-n": { + "version": "15.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "builtins": "^5.0.1", + "eslint-plugin-es": "^4.1.0", + "eslint-utils": "^3.0.0", + "ignore": "^5.1.1", + "is-core-module": "^2.11.0", + "minimatch": "^3.1.2", + "resolve": "^1.22.1", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-promise": { + "version": "6.6.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.6", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "dev": true, + "license": "BSD-2-Clause", + "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-utils": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "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/eslint/node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "dev": true, + "license": "BSD-2-Clause", + "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.7.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-content-type-parse": { + "version": "3.0.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/figures": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-versions": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver-regex": "^4.0.5", + "super-regex": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "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.3.4", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/from2": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/fs-extra": { + "version": "11.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "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, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function-timeout": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.5.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stdin": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/git-log-parser": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "argv-formatter": "~1.0.0", + "spawn-error-forwarder": "~1.0.0", + "split2": "~1.0.0", + "stream-combiner2": "~1.1.1", + "through2": "~2.0.0", + "traverse": "0.6.8" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globals/node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/hook-std": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hosted-git-info": { + "version": "9.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-from-esm": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "import-meta-resolve": "^4.0.0" + }, + "engines": { + "node": ">=18.20" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/index-to-position": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "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==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "dev": true, + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/into-stream": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/issue-parser": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.capitalize": "^4.2.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.uniqby": "^4.7.0" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/java-properties": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-with-bigint": { + "version": "3.5.7", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "dev": true, + "license": "MIT" + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.23", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.23", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.capitalize": { + "version": "4.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniqby": { + "version": "4.7.0", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "11.2.6", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/make-asynchronous": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-event": "^6.0.0", + "type-fest": "^4.6.0", + "web-worker": "^1.5.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-asynchronous/node_modules/type-fest": { + "version": "4.41.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/marked": { + "version": "15.0.12", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/marked-terminal": { + "version": "7.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "ansi-regex": "^6.1.0", + "chalk": "^5.4.1", + "cli-highlight": "^2.1.11", + "cli-table3": "^0.6.5", + "node-emoji": "^2.2.0", + "supports-hyperlinks": "^3.1.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "marked": ">=1 <16" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meow": { + "version": "13.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "4.1.0", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa" + ], + "license": "MIT", + "bin": { + "mime": "bin/cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/neo-async": { + "version": "2.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/nerf-dart": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/node-emoji": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-exports-info": { + "version": "1.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-exports-info/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/normalize-package-data": { + "version": "8.0.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^9.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/normalize-url": { + "version": "9.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm": { + "version": "11.11.0", + "bundleDependencies": [ + "@isaacs/string-locale-compare", + "@npmcli/arborist", + "@npmcli/config", + "@npmcli/fs", + "@npmcli/map-workspaces", + "@npmcli/metavuln-calculator", + "@npmcli/package-json", + "@npmcli/promise-spawn", + "@npmcli/redact", + "@npmcli/run-script", + "@sigstore/tuf", + "abbrev", + "archy", + "cacache", + "chalk", + "ci-info", + "fastest-levenshtein", + "fs-minipass", + "glob", + "graceful-fs", + "hosted-git-info", + "ini", + "init-package-json", + "is-cidr", + "json-parse-even-better-errors", + "libnpmaccess", + "libnpmdiff", + "libnpmexec", + "libnpmfund", + "libnpmorg", + "libnpmpack", + "libnpmpublish", + "libnpmsearch", + "libnpmteam", + "libnpmversion", + "make-fetch-happen", + "minimatch", + "minipass", + "minipass-pipeline", + "ms", + "node-gyp", + "nopt", + "npm-audit-report", + "npm-install-checks", + "npm-package-arg", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "p-map", + "pacote", + "parse-conflict-json", + "proc-log", + "qrcode-terminal", + "read", + "semver", + "spdx-expression-parse", + "ssri", + "supports-color", + "tar", + "text-table", + "tiny-relative-date", + "treeverse", + "validate-npm-package-name", + "which" + ], + "dev": true, + "license": "Artistic-2.0", + "workspaces": [ + "docs", + "smoke-tests", + "mock-globals", + "mock-registry", + "workspaces/*" + ], + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^9.4.0", + "@npmcli/config": "^10.7.1", + "@npmcli/fs": "^5.0.0", + "@npmcli/map-workspaces": "^5.0.3", + "@npmcli/metavuln-calculator": "^9.0.3", + "@npmcli/package-json": "^7.0.5", + "@npmcli/promise-spawn": "^9.0.1", + "@npmcli/redact": "^4.0.0", + "@npmcli/run-script": "^10.0.3", + "@sigstore/tuf": "^4.0.1", + "abbrev": "^4.0.0", + "archy": "~1.0.0", + "cacache": "^20.0.3", + "chalk": "^5.6.2", + "ci-info": "^4.4.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.3", + "glob": "^13.0.6", + "graceful-fs": "^4.2.11", + "hosted-git-info": "^9.0.2", + "ini": "^6.0.0", + "init-package-json": "^8.2.5", + "is-cidr": "^6.0.3", + "json-parse-even-better-errors": "^5.0.0", + "libnpmaccess": "^10.0.3", + "libnpmdiff": "^8.1.3", + "libnpmexec": "^10.2.3", + "libnpmfund": "^7.0.17", + "libnpmorg": "^8.0.1", + "libnpmpack": "^9.1.3", + "libnpmpublish": "^11.1.3", + "libnpmsearch": "^9.0.1", + "libnpmteam": "^8.0.2", + "libnpmversion": "^8.0.3", + "make-fetch-happen": "^15.0.4", + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^12.2.0", + "nopt": "^9.0.0", + "npm-audit-report": "^7.0.0", + "npm-install-checks": "^8.0.0", + "npm-package-arg": "^13.0.2", + "npm-pick-manifest": "^11.0.3", + "npm-profile": "^12.0.1", + "npm-registry-fetch": "^19.1.1", + "npm-user-validate": "^4.0.0", + "p-map": "^7.0.4", + "pacote": "^21.4.0", + "parse-conflict-json": "^5.0.1", + "proc-log": "^6.1.0", + "qrcode-terminal": "^0.12.0", + "read": "^5.0.1", + "semver": "^7.7.4", + "spdx-expression-parse": "^4.0.0", + "ssri": "^13.0.1", + "supports-color": "^10.2.2", + "tar": "^7.5.9", + "text-table": "~0.2.0", + "tiny-relative-date": "^2.0.2", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^7.0.2", + "which": "^6.0.1" + }, + "bin": { + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/@gar/promise-retry": { + "version": "1.0.2", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "retry": "^0.13.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@gar/promise-retry/node_modules/retry": { + "version": "0.13.1", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/npm/node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "extraneous": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/agent": { + "version": "4.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^11.2.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/arborist": { + "version": "9.4.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^5.0.0", + "@npmcli/installed-package-contents": "^4.0.0", + "@npmcli/map-workspaces": "^5.0.0", + "@npmcli/metavuln-calculator": "^9.0.2", + "@npmcli/name-from-folder": "^4.0.0", + "@npmcli/node-gyp": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/query": "^5.0.0", + "@npmcli/redact": "^4.0.0", + "@npmcli/run-script": "^10.0.0", + "bin-links": "^6.0.0", + "cacache": "^20.0.1", + "common-ancestor-path": "^2.0.0", + "hosted-git-info": "^9.0.0", + "json-stringify-nice": "^1.1.4", + "lru-cache": "^11.2.1", + "minimatch": "^10.0.3", + "nopt": "^9.0.0", + "npm-install-checks": "^8.0.0", + "npm-package-arg": "^13.0.0", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "pacote": "^21.0.2", + "parse-conflict-json": "^5.0.1", + "proc-log": "^6.0.0", + "proggy": "^4.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^3.0.1", + "semver": "^7.3.7", + "ssri": "^13.0.0", + "treeverse": "^3.0.0", + "walk-up-path": "^4.0.0" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/config": { + "version": "10.7.1", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/map-workspaces": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "ci-info": "^4.0.0", + "ini": "^6.0.0", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "walk-up-path": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/fs": { + "version": "5.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/git": { + "version": "7.0.2", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "ini": "^6.0.0", + "lru-cache": "^11.2.1", + "npm-pick-manifest": "^11.0.1", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "which": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/installed-package-contents": { + "version": "4.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^5.0.0", + "npm-normalize-package-bin": "^5.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/map-workspaces": { + "version": "5.0.3", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^4.0.0", + "@npmcli/package-json": "^7.0.0", + "glob": "^13.0.0", + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "9.0.3", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cacache": "^20.0.0", + "json-parse-even-better-errors": "^5.0.0", + "pacote": "^21.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "4.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "5.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/package-json": { + "version": "7.0.5", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^7.0.0", + "glob": "^13.0.0", + "hosted-git-info": "^9.0.0", + "json-parse-even-better-errors": "^5.0.0", + "proc-log": "^6.0.0", + "semver": "^7.5.3", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "9.0.1", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "which": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/query": { + "version": "5.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/redact": { + "version": "4.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "10.0.3", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "node-gyp": "^12.1.0", + "proc-log": "^6.0.0", + "which": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/bundle": { + "version": "4.0.0", + "extraneous": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/core": { + "version": "3.1.0", + "extraneous": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/protobuf-specs": { + "version": "0.5.0", + "extraneous": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@sigstore/sign": { + "version": "4.1.0", + "extraneous": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.1.0", + "@sigstore/protobuf-specs": "^0.5.0", + "make-fetch-happen": "^15.0.3", + "proc-log": "^6.1.0", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/tuf": { + "version": "4.0.1", + "extraneous": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0", + "tuf-js": "^4.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/verify": { + "version": "3.1.0", + "extraneous": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.1.0", + "@sigstore/protobuf-specs": "^0.5.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@tufjs/models": { + "version": "4.1.0", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^10.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/abbrev": { + "version": "4.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/agent-base": { + "version": "7.1.4", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/aproba": { + "version": "2.1.0", + "extraneous": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "extraneous": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "4.0.4", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/npm/node_modules/bin-links": { + "version": "6.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cmd-shim": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "proc-log": "^6.0.0", + "read-cmd-shim": "^6.0.0", + "write-file-atomic": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/binary-extensions": { + "version": "3.1.0", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/brace-expansion": { + "version": "5.0.3", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/npm/node_modules/cacache": { + "version": "20.0.3", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^5.0.0", + "fs-minipass": "^3.0.0", + "glob": "^13.0.0", + "lru-cache": "^11.1.0", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^13.0.0", + "unique-filename": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/chalk": { + "version": "5.6.2", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm/node_modules/chownr": { + "version": "3.0.0", + "extraneous": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/ci-info": { + "version": "4.4.0", + "extraneous": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cidr-regex": { + "version": "5.0.3", + "extraneous": true, + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/npm/node_modules/cmd-shim": { + "version": "8.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/common-ancestor-path": { + "version": "2.0.0", + "extraneous": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">= 18" + } + }, + "node_modules/npm/node_modules/cssesc": { + "version": "3.0.0", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/debug": { + "version": "4.4.3", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/diff": { + "version": "8.0.3", + "extraneous": true, + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/err-code": { + "version": "2.0.3", + "extraneous": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/exponential-backoff": { + "version": "3.1.3", + "extraneous": true, + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.16", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/npm/node_modules/fs-minipass": { + "version": "3.0.3", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/glob": { + "version": "13.0.6", + "extraneous": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/graceful-fs": { + "version": "4.2.11", + "extraneous": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/hosted-git-info": { + "version": "9.0.2", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/http-cache-semantics": { + "version": "4.2.0", + "extraneous": true, + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/http-proxy-agent": { + "version": "7.0.2", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/https-proxy-agent": { + "version": "7.0.6", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/iconv-lite": { + "version": "0.7.2", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/npm/node_modules/ignore-walk": { + "version": "8.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/imurmurhash": { + "version": "0.1.4", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/npm/node_modules/ini": { + "version": "6.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/init-package-json": { + "version": "8.2.5", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/package-json": "^7.0.0", + "npm-package-arg": "^13.0.0", + "promzard": "^3.0.1", + "read": "^5.0.1", + "semver": "^7.7.2", + "validate-npm-package-name": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/ip-address": { + "version": "10.1.0", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/npm/node_modules/is-cidr": { + "version": "6.0.3", + "extraneous": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "cidr-regex": "^5.0.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/npm/node_modules/isexe": { + "version": "4.0.0", + "extraneous": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "5.0.0", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/json-stringify-nice": { + "version": "1.1.4", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "engines": [ + "node >= 0.2.0" + ], + "extraneous": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff": { + "version": "6.0.2", + "extraneous": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff-apply": { + "version": "5.5.0", + "extraneous": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/libnpmaccess": { + "version": "10.0.3", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^13.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmdiff": { + "version": "8.1.3", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^9.4.0", + "@npmcli/installed-package-contents": "^4.0.0", + "binary-extensions": "^3.0.0", + "diff": "^8.0.2", + "minimatch": "^10.0.3", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2", + "tar": "^7.5.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmexec": { + "version": "10.2.3", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/arborist": "^9.4.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/run-script": "^10.0.0", + "ci-info": "^4.0.0", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2", + "proc-log": "^6.0.0", + "read": "^5.0.1", + "semver": "^7.3.7", + "signal-exit": "^4.1.0", + "walk-up-path": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmfund": { + "version": "7.0.17", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^9.4.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmorg": { + "version": "8.0.1", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmpack": { + "version": "9.1.3", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^9.4.0", + "@npmcli/run-script": "^10.0.0", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmpublish": { + "version": "11.1.3", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/package-json": "^7.0.0", + "ci-info": "^4.0.0", + "npm-package-arg": "^13.0.0", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.7", + "sigstore": "^4.0.0", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmsearch": { + "version": "9.0.1", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmteam": { + "version": "8.0.2", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmversion": { + "version": "8.0.3", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^7.0.0", + "@npmcli/run-script": "^10.0.0", + "json-parse-even-better-errors": "^5.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/lru-cache": { + "version": "11.2.6", + "extraneous": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/npm/node_modules/make-fetch-happen": { + "version": "15.0.4", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/agent": "^4.0.0", + "cacache": "^20.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^6.0.0", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/minimatch": { + "version": "10.2.2", + "extraneous": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/minipass": { + "version": "7.1.3", + "extraneous": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-collect": { + "version": "2.0.1", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-fetch": { + "version": "5.0.2", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^2.0.0", + "minizlib": "^3.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + }, + "optionalDependencies": { + "iconv-lite": "^0.7.2" + } + }, + "node_modules/npm/node_modules/minipass-flush": { + "version": "1.0.5", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/minipass-sized": { + "version": "2.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minizlib": { + "version": "3.1.0", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "extraneous": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "3.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/negotiator": { + "version": "1.0.0", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "12.2.0", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^15.0.0", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "tar": "^7.5.4", + "tinyglobby": "^0.2.12", + "which": "^6.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/nopt": { + "version": "9.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "^4.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-audit-report": { + "version": "7.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-bundled": { + "version": "5.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-install-checks": { + "version": "8.0.0", + "extraneous": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-normalize-package-bin": { + "version": "5.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-package-arg": { + "version": "13.0.2", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-packlist": { + "version": "10.0.4", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^8.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-pick-manifest": { + "version": "11.0.3", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "npm-package-arg": "^13.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-profile": { + "version": "12.0.1", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch": { + "version": "19.1.1", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/redact": "^4.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^15.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^13.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-user-validate": { + "version": "4.0.0", + "extraneous": true, + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/p-map": { + "version": "7.0.4", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/pacote": { + "version": "21.4.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/git": "^7.0.0", + "@npmcli/installed-package-contents": "^4.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "@npmcli/run-script": "^10.0.0", + "cacache": "^20.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^13.0.0", + "npm-packlist": "^10.0.1", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0", + "sigstore": "^4.0.0", + "ssri": "^13.0.0", + "tar": "^7.4.3" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/parse-conflict-json": { + "version": "5.0.1", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^5.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/path-scurry": { + "version": "2.0.2", + "extraneous": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/proc-log": { + "version": "6.1.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/proggy": { + "version": "4.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/promise-all-reject-late": { + "version": "1.0.1", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-call-limit": { + "version": "3.0.2", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-retry": { + "version": "2.0.1", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/promzard": { + "version": "3.0.1", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "read": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "extraneous": true, + "inBundle": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/npm/node_modules/read": { + "version": "5.0.1", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "mute-stream": "^3.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/read-cmd-shim": { + "version": "6.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/retry": { + "version": "0.12.0", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "extraneous": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/semver": { + "version": "7.7.4", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/signal-exit": { + "version": "4.1.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/sigstore": { + "version": "4.1.0", + "extraneous": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.1.0", + "@sigstore/protobuf-specs": "^0.5.0", + "@sigstore/sign": "^4.1.0", + "@sigstore/tuf": "^4.0.1", + "@sigstore/verify": "^3.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/smart-buffer": { + "version": "4.2.0", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks": { + "version": "2.8.7", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks-proxy-agent": { + "version": "8.0.5", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.5.0", + "extraneous": true, + "inBundle": true, + "license": "CC-BY-3.0" + }, + "node_modules/npm/node_modules/spdx-expression-parse": { + "version": "4.0.0", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.23", + "extraneous": true, + "inBundle": true, + "license": "CC0-1.0" + }, + "node_modules/npm/node_modules/ssri": { + "version": "13.0.1", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/supports-color": { + "version": "10.2.2", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/npm/node_modules/tar": { + "version": "7.5.9", + "extraneous": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "extraneous": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "2.0.2", + "extraneous": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tinyglobby": { + "version": "0.2.15", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/npm/node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/npm/node_modules/treeverse": { + "version": "3.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/tuf-js": { + "version": "4.1.0", + "extraneous": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/models": "4.1.0", + "debug": "^4.4.3", + "make-fetch-happen": "^15.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/unique-filename": { + "version": "5.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/unique-slug": { + "version": "6.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/util-deprecate": { + "version": "1.0.2", + "extraneous": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "7.0.2", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/walk-up-path": { + "version": "4.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/npm/node_modules/which": { + "version": "6.0.1", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/write-file-atomic": { + "version": "7.0.0", + "extraneous": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/yallist": { + "version": "5.0.0", + "extraneous": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-each-series": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-event": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-filter": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-map": "^7.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-is-promise": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-map": { + "version": "7.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-reduce": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-timeout": { + "version": "6.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-ms": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-ms": { + "version": "9.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "dev": true, + "license": "ISC" + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "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" + } + ], + "license": "MIT" + }, + "node_modules/rc": { + "version": "1.2.8", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "dev": true, + "license": "MIT" + }, + "node_modules/read-package-up": { + "version": "12.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.1", + "read-pkg": "^10.0.0", + "type-fest": "^5.2.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg": { + "version": "10.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.4", + "normalize-package-data": "^8.0.0", + "parse-json": "^8.3.0", + "type-fest": "^5.4.4", + "unicorn-magic": "^0.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/parse-json": { + "version": "8.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/parse-json/node_modules/type-fest": { + "version": "4.41.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/registry-auth-token": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/npm-conf": "^3.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "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/run-parallel": { + "version": "1.2.0", + "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" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply/node_modules/isarray": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semantic-release": { + "version": "25.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@semantic-release/commit-analyzer": "^13.0.1", + "@semantic-release/error": "^4.0.0", + "@semantic-release/github": "^12.0.0", + "@semantic-release/npm": "^13.1.1", + "@semantic-release/release-notes-generator": "^14.1.0", + "aggregate-error": "^5.0.0", + "cosmiconfig": "^9.0.0", + "debug": "^4.0.0", + "env-ci": "^11.0.0", + "execa": "^9.0.0", + "figures": "^6.0.0", + "find-versions": "^6.0.0", + "get-stream": "^6.0.0", + "git-log-parser": "^1.2.0", + "hook-std": "^4.0.0", + "hosted-git-info": "^9.0.0", + "import-from-esm": "^2.0.0", + "lodash-es": "^4.17.21", + "marked": "^15.0.0", + "marked-terminal": "^7.3.0", + "micromatch": "^4.0.2", + "p-each-series": "^3.0.0", + "p-reduce": "^3.0.0", + "read-package-up": "^12.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.3.2", + "signale": "^1.2.1", + "yargs": "^18.0.0" + }, + "bin": { + "semantic-release": "bin/semantic-release.js" + }, + "engines": { + "node": "^22.14.0 || >= 24.10.0" + } + }, + "node_modules/semantic-release/node_modules/@semantic-release/error": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/semantic-release/node_modules/aggregate-error": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/clean-stack": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/escape-string-regexp": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/execa": { + "version": "9.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/semantic-release/node_modules/execa/node_modules/get-stream": { + "version": "9.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/human-signals": { + "version": "8.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/semantic-release/node_modules/indent-string": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/is-stream": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/npm-run-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/p-reduce": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/path-key": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semantic-release/node_modules/strip-final-newline": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/unicorn-magic": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-regex": { + "version": "4.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/signale": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.3.2", + "figures": "^2.0.0", + "pkg-conf": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/signale/node_modules/ansi-styles": { + "version": "3.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/chalk": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/color-convert": { + "version": "1.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/signale/node_modules/color-name": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/signale/node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/signale/node_modules/figures": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "license": "MIT" + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawn-error-forwarder": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/split2": { + "version": "1.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "through2": "~2.0.0" + } + }, + "node_modules/standard": { + "version": "17.1.2", + "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" + } + ], + "license": "MIT", + "dependencies": { + "eslint": "^8.41.0", + "eslint-config-standard": "17.1.0", + "eslint-config-standard-jsx": "^11.0.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-n": "^15.7.0", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-react": "^7.36.1", + "standard-engine": "^15.1.0", + "version-guard": "^1.1.1" + }, + "bin": { + "standard": "bin/cmd.cjs" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/standard-engine": { + "version": "15.1.0", + "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" + } + ], + "license": "MIT", + "dependencies": { + "get-stdin": "^8.0.0", + "minimist": "^1.2.6", + "pkg-conf": "^3.1.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/standard-engine/node_modules/find-up": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-engine/node_modules/load-json-file": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-engine/node_modules/locate-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-engine/node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/standard-engine/node_modules/p-locate": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-engine/node_modules/p-try": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-engine/node_modules/parse-json": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/standard-engine/node_modules/pify": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-engine/node_modules/pkg-conf": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0", + "load-json-file": "^5.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-engine/node_modules/type-fest": { + "version": "0.3.1", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=6" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stream-combiner2": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/super-regex": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "function-timeout": "^1.0.1", + "make-asynchronous": "^1.0.1", + "time-span": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tar": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz", + "integrity": "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/temp-dir": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/tempy": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^3.0.0", + "temp-dir": "^3.0.0", + "type-fest": "^2.12.2", + "unique-string": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/is-stream": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "2.19.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/thenify": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/time-span": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "convert-hrtime": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/traverse": { + "version": "0.6.8", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "5.4.4", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici": { + "version": "7.22.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicorn-magic": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universal-user-agent": { + "version": "7.0.3", + "dev": true, + "license": "ISC" + }, + "node_modules/universalify": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-join": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/version-guard": { + "version": "1.1.3", + "dev": true, + "license": "0BSD", + "engines": { + "node": ">=0.10.48" + } + }, + "node_modules/web-worker": { + "version": "1.5.0", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/which-collection": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "10.6.0", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "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, + "license": "ISC" + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/yargs": { + "version": "18.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "10.6.0", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json index a2e2026..e92962e 100644 --- a/package.json +++ b/package.json @@ -19,15 +19,15 @@ "commander": "^14.0.3", "glob": "^13.0.0", "prompts": "^2.4.2", - "semver": "^7.7.4" + "semver": "^7.7.4", + "tar": "^7.5.13" }, "prerequisites": { - "git": ">=2", "node": "24", "npm": "10" }, "scripts": { - "test": "node --test 'tests/**/*.spec.js'" + "test": "node --experimental-test-module-mocks --test 'tests/**/*.spec.js'" }, "publishConfig": { "access": "public" diff --git a/tests/downloadRelease.spec.js b/tests/downloadRelease.spec.js new file mode 100644 index 0000000..d678839 --- /dev/null +++ b/tests/downloadRelease.spec.js @@ -0,0 +1,110 @@ +import { describe, it, before, after, beforeEach, afterEach, mock } from 'node:test' +import assert from 'node:assert/strict' +import fs from 'fs/promises' +import os from 'os' +import path from 'path' +import { Readable } from 'stream' +import { createGzip } from 'zlib' +import { pipeline } from 'stream/promises' +import { create } from 'tar' + +// mock exec before importing downloadRelease +mock.module('../lib/utils/exec.js', { + defaultExport: async () => {} +}) + +const { default: downloadRelease } = await import('../lib/utils/downloadRelease.js') + +describe('downloadRelease', () => { + let tmpDir, originalFetch, tarballBuffer + + before(async () => { + originalFetch = globalThis.fetch + + // create a small tarball in memory with a top-level directory (like GitHub produces) + const srcDir = await fs.mkdtemp(path.join(os.tmpdir(), 'aat-tar-src-')) + const innerDir = path.join(srcDir, 'adapt-security-adapt-authoring-abc1234') + await fs.mkdir(innerDir, { recursive: true }) + await fs.writeFile(path.join(innerDir, 'package.json'), '{"name":"test"}') + await fs.writeFile(path.join(innerDir, 'index.js'), 'console.log("hello")') + + const chunks = [] + const pack = create({ cwd: srcDir, gzip: false }, ['adapt-security-adapt-authoring-abc1234']) + const gzip = createGzip() + const collect = new (await import('stream')).Writable({ + write (chunk, enc, cb) { chunks.push(chunk); cb() } + }) + await pipeline(pack, gzip, collect) + tarballBuffer = Buffer.concat(chunks) + + await fs.rm(srcDir, { recursive: true, force: true }) + }) + + after(() => { + globalThis.fetch = originalFetch + }) + + beforeEach(async () => { + tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'aat-dl-test-')) + }) + + afterEach(async () => { + await fs.rm(tmpDir, { recursive: true, force: true }) + }) + + it('should extract tarball contents to targetDir', async () => { + globalThis.fetch = async () => ({ + ok: true, + body: Readable.from(tarballBuffer) + }) + const targetDir = path.join(tmpDir, 'app') + await downloadRelease({ tag: 'v1.0.0', targetDir }) + + const pkg = JSON.parse(await fs.readFile(path.join(targetDir, 'package.json'), 'utf8')) + assert.equal(pkg.name, 'test') + const index = await fs.readFile(path.join(targetDir, 'index.js'), 'utf8') + assert.equal(index, 'console.log("hello")') + }) + + it('should strip the top-level directory from the tarball', async () => { + globalThis.fetch = async () => ({ + ok: true, + body: Readable.from(tarballBuffer) + }) + const targetDir = path.join(tmpDir, 'app') + await downloadRelease({ tag: 'v1.0.0', targetDir }) + + // should not have the nested github directory + const files = await fs.readdir(targetDir) + assert.ok(!files.includes('adapt-security-adapt-authoring-abc1234')) + assert.ok(files.includes('package.json')) + }) + + it('should throw on non-ok response', async () => { + globalThis.fetch = async () => ({ + ok: false, + status: 404, + statusText: 'Not Found' + }) + const targetDir = path.join(tmpDir, 'app') + await assert.rejects( + downloadRelease({ tag: 'v1.0.0', targetDir }), + e => { + assert.match(e.message, /Failed to download/) + assert.match(e.message, /404/) + return true + } + ) + }) + + it('should create the targetDir if it does not exist', async () => { + globalThis.fetch = async () => ({ + ok: true, + body: Readable.from(tarballBuffer) + }) + const targetDir = path.join(tmpDir, 'nested', 'deep', 'app') + await downloadRelease({ tag: 'v1.0.0', targetDir }) + const stat = await fs.stat(targetDir) + assert.ok(stat.isDirectory()) + }) +}) diff --git a/tests/getInstalledVersion.spec.js b/tests/getInstalledVersion.spec.js new file mode 100644 index 0000000..6d8d46e --- /dev/null +++ b/tests/getInstalledVersion.spec.js @@ -0,0 +1,62 @@ +import { describe, it, beforeEach, afterEach } from 'node:test' +import assert from 'node:assert/strict' +import fs from 'fs/promises' +import path from 'path' +import os from 'os' +import getInstalledVersion, { writeInstalledVersion } from '../lib/utils/getInstalledVersion.js' + +describe('getInstalledVersion', () => { + let tmpDir + + beforeEach(async () => { + tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'aat-test-')) + await fs.mkdir(path.join(tmpDir, 'conf'), { recursive: true }) + }) + + afterEach(async () => { + await fs.rm(tmpDir, { recursive: true, force: true }) + }) + + it('should return null when no version file exists', async () => { + const version = await getInstalledVersion(tmpDir) + assert.equal(version, null) + }) + + it('should return the version string when file exists', async () => { + await fs.writeFile(path.join(tmpDir, 'conf', '.version'), 'v1.2.3') + const version = await getInstalledVersion(tmpDir) + assert.equal(version, 'v1.2.3') + }) + + it('should trim whitespace from version string', async () => { + await fs.writeFile(path.join(tmpDir, 'conf', '.version'), ' v1.2.3\n') + const version = await getInstalledVersion(tmpDir) + assert.equal(version, 'v1.2.3') + }) +}) + +describe('writeInstalledVersion', () => { + let tmpDir + + beforeEach(async () => { + tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'aat-test-')) + await fs.mkdir(path.join(tmpDir, 'conf'), { recursive: true }) + }) + + afterEach(async () => { + await fs.rm(tmpDir, { recursive: true, force: true }) + }) + + it('should write the version file', async () => { + await writeInstalledVersion(tmpDir, 'v2.0.0') + const content = await fs.readFile(path.join(tmpDir, 'conf', '.version'), 'utf8') + assert.equal(content, 'v2.0.0') + }) + + it('should overwrite an existing version file', async () => { + await writeInstalledVersion(tmpDir, 'v1.0.0') + await writeInstalledVersion(tmpDir, 'v2.0.0') + const content = await fs.readFile(path.join(tmpDir, 'conf', '.version'), 'utf8') + assert.equal(content, 'v2.0.0') + }) +}) diff --git a/tests/installState.spec.js b/tests/installState.spec.js deleted file mode 100644 index e43ad62..0000000 --- a/tests/installState.spec.js +++ /dev/null @@ -1,60 +0,0 @@ -import { describe, it, beforeEach, afterEach } from 'node:test' -import assert from 'node:assert/strict' -import fs from 'node:fs/promises' -import path from 'node:path' -import os from 'node:os' -import { getInstallState, saveInstallState, clearInstallState } from '../lib/utils/installState.js' - -describe('installState', () => { - let tmpDir - - beforeEach(async () => { - tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'install-state-')) - }) - - afterEach(async () => { - await fs.rm(tmpDir, { recursive: true, force: true }) - }) - - describe('#getInstallState()', () => { - it('should return null when no state file exists', async () => { - assert.equal(await getInstallState(tmpDir), null) - }) - - it('should return parsed state when file exists', async () => { - await fs.writeFile(path.join(tmpDir, '.install-state.json'), JSON.stringify({ step: 4, selectedRelease: 'v1.0.0' })) - const state = await getInstallState(tmpDir) - assert.equal(state.step, 4) - assert.equal(state.selectedRelease, 'v1.0.0') - }) - }) - - describe('#saveInstallState()', () => { - it('should create the state file in the root directory', async () => { - await saveInstallState(tmpDir, { step: 3, selectedRelease: 'v2.0.0' }) - const state = JSON.parse(await fs.readFile(path.join(tmpDir, '.install-state.json'), 'utf8')) - assert.equal(state.step, 3) - assert.equal(state.selectedRelease, 'v2.0.0') - assert.ok(state.timestamp) - }) - - it('should overwrite existing state', async () => { - await saveInstallState(tmpDir, { step: 2 }) - await saveInstallState(tmpDir, { step: 5 }) - const state = await getInstallState(tmpDir) - assert.equal(state.step, 5) - }) - }) - - describe('#clearInstallState()', () => { - it('should remove the state file', async () => { - await saveInstallState(tmpDir, { step: 4 }) - await clearInstallState(tmpDir) - assert.equal(await getInstallState(tmpDir), null) - }) - - it('should not throw when no state file exists', async () => { - await assert.doesNotReject(() => clearInstallState(tmpDir)) - }) - }) -}) diff --git a/tests/swapInstall.spec.js b/tests/swapInstall.spec.js new file mode 100644 index 0000000..5cba763 --- /dev/null +++ b/tests/swapInstall.spec.js @@ -0,0 +1,59 @@ +import { describe, it, beforeEach, afterEach } from 'node:test' +import assert from 'node:assert/strict' +import fs from 'fs/promises' +import path from 'path' +import os from 'os' +import swapInstall from '../lib/utils/swapInstall.js' + +describe('swapInstall', () => { + let tmpDir, targetDir, stagingDir + + beforeEach(async () => { + tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'aat-test-')) + targetDir = path.join(tmpDir, 'app') + stagingDir = path.join(tmpDir, 'staging') + + // create a target install with conf/ and a file + await fs.mkdir(path.join(targetDir, 'conf'), { recursive: true }) + await fs.writeFile(path.join(targetDir, 'conf', 'production.config.js'), 'export default {}') + await fs.writeFile(path.join(targetDir, 'index.js'), 'old version') + + // create a staging install with new code + await fs.mkdir(stagingDir, { recursive: true }) + await fs.writeFile(path.join(stagingDir, 'index.js'), 'new version') + }) + + afterEach(async () => { + await fs.rm(tmpDir, { recursive: true, force: true }) + }) + + it('should copy conf/ from target into staging', async () => { + await swapInstall({ stagingDir, targetDir, version: 'v1.0.0' }) + const config = await fs.readFile(path.join(targetDir, 'conf', 'production.config.js'), 'utf8') + assert.equal(config, 'export default {}') + }) + + it('should replace target with staging contents', async () => { + await swapInstall({ stagingDir, targetDir, version: 'v1.0.0' }) + const content = await fs.readFile(path.join(targetDir, 'index.js'), 'utf8') + assert.equal(content, 'new version') + }) + + it('should remove the backup directory', async () => { + await swapInstall({ stagingDir, targetDir, version: 'v1.0.0' }) + const backupDir = `${targetDir}.backup-v1.0.0` + await assert.rejects(() => fs.access(backupDir)) + }) + + it('should remove the staging directory', async () => { + await swapInstall({ stagingDir, targetDir, version: 'v1.0.0' }) + await assert.rejects(() => fs.access(stagingDir)) + }) + + it('should preserve all files in conf/', async () => { + await fs.writeFile(path.join(targetDir, 'conf', '.version'), 'v1.0.0') + await swapInstall({ stagingDir, targetDir, version: 'v1.0.0' }) + const version = await fs.readFile(path.join(targetDir, 'conf', '.version'), 'utf8') + assert.equal(version, 'v1.0.0') + }) +}) From 4f0554d02e6655ba9699af5b38ad00f6d0774649 Mon Sep 17 00:00:00 2001 From: Thomas Taylor Date: Sat, 28 Mar 2026 20:18:09 +0000 Subject: [PATCH 03/14] Chore: Move peerDeps and versionCompare into lib/utils Both are utility modules that belong alongside the other utils, not sitting directly in lib/ next to the classes. --- bin/deps-check.js | 2 +- bin/deps-gen.js | 2 +- bin/release-notes.js | 2 +- bin/version-check.js | 2 +- lib/utils/getReleases.js | 2 +- lib/{ => utils}/peerDeps.js | 2 +- lib/{ => utils}/versionCompare.js | 0 tests/peerDeps.spec.js | 2 +- tests/versionCompare.spec.js | 2 +- 9 files changed, 8 insertions(+), 8 deletions(-) rename lib/{ => utils}/peerDeps.js (95%) rename lib/{ => utils}/versionCompare.js (100%) diff --git a/bin/deps-check.js b/bin/deps-check.js index 062a333..6ef417c 100644 --- a/bin/deps-check.js +++ b/bin/deps-check.js @@ -4,7 +4,7 @@ import buildPackageIndex from '../lib/utils/buildPackageIndex.js' import CliCommand from '../lib/CliCommand.js' import getModuleDirs from '../lib/utils/getModuleDirs.js' import isModule from '../lib/utils/isModule.js' -import { isAdaptModule, deriveExpectedPeerDeps, deriveExpectedDeps, findOutdatedVersions } from '../lib/peerDeps.js' +import { isAdaptModule, deriveExpectedPeerDeps, deriveExpectedDeps, findOutdatedVersions } from '../lib/utils/peerDeps.js' const CORE_PKG = 'adapt-authoring-core' diff --git a/bin/deps-gen.js b/bin/deps-gen.js index ab1733b..6c59d9f 100644 --- a/bin/deps-gen.js +++ b/bin/deps-gen.js @@ -5,7 +5,7 @@ import CliCommand from '../lib/CliCommand.js' import exec from '../lib/utils/exec.js' import getModuleDirs from '../lib/utils/getModuleDirs.js' import isModule from '../lib/utils/isModule.js' -import { isAdaptModule, deriveExpectedPeerDeps, deriveExpectedDeps, findOutdatedVersions } from '../lib/peerDeps.js' +import { isAdaptModule, deriveExpectedPeerDeps, deriveExpectedDeps, findOutdatedVersions } from '../lib/utils/peerDeps.js' const CORE_PKG = 'adapt-authoring-core' diff --git a/bin/release-notes.js b/bin/release-notes.js index fc7868e..54c4377 100644 --- a/bin/release-notes.js +++ b/bin/release-notes.js @@ -2,7 +2,7 @@ import { readFileSync } from 'node:fs' import { join } from 'node:path' import semver from 'semver' import CliCommand from '../lib/CliCommand.js' -import { compareVersions } from '../lib/versionCompare.js' +import { compareVersions } from '../lib/utils/versionCompare.js' export default class ReleaseNotes extends CliCommand { get config () { diff --git a/bin/version-check.js b/bin/version-check.js index 5d45931..da10a60 100644 --- a/bin/version-check.js +++ b/bin/version-check.js @@ -1,5 +1,5 @@ import CliCommand from '../lib/CliCommand.js' -import { compareVersions } from '../lib/versionCompare.js' +import { compareVersions } from '../lib/utils/versionCompare.js' export default class VersionCheck extends CliCommand { get config () { diff --git a/lib/utils/getReleases.js b/lib/utils/getReleases.js index e64237d..506dc07 100644 --- a/lib/utils/getReleases.js +++ b/lib/utils/getReleases.js @@ -1,6 +1,6 @@ import githubRequest from './githubRequest.js' import semver from 'semver' -import { normalizeBump } from '../versionCompare.js' +import { normalizeBump } from './versionCompare.js' export default async function getReleases (options) { const releases = (await githubRequest('releases?per_page=10')) diff --git a/lib/peerDeps.js b/lib/utils/peerDeps.js similarity index 95% rename from lib/peerDeps.js rename to lib/utils/peerDeps.js index 80d0911..5a6aa7a 100644 --- a/lib/peerDeps.js +++ b/lib/utils/peerDeps.js @@ -1,6 +1,6 @@ import { readFileSync, existsSync, statSync } from 'node:fs' import { join } from 'node:path' -import collectJsFiles from './utils/collectJsFiles.js' +import collectJsFiles from './collectJsFiles.js' export const PREFIX = 'adapt-authoring-' diff --git a/lib/versionCompare.js b/lib/utils/versionCompare.js similarity index 100% rename from lib/versionCompare.js rename to lib/utils/versionCompare.js diff --git a/tests/peerDeps.spec.js b/tests/peerDeps.spec.js index 44998c8..e7e5e38 100644 --- a/tests/peerDeps.spec.js +++ b/tests/peerDeps.spec.js @@ -10,7 +10,7 @@ import { extractImportedModules, toFullName, findOutdatedVersions -} from '../lib/peerDeps.js' +} from '../lib/utils/peerDeps.js' describe('peerDeps', () => { describe('PREFIX', () => { diff --git a/tests/versionCompare.spec.js b/tests/versionCompare.spec.js index 65bc347..ceb8663 100644 --- a/tests/versionCompare.spec.js +++ b/tests/versionCompare.spec.js @@ -1,6 +1,6 @@ import { describe, it } from 'node:test' import assert from 'node:assert/strict' -import { BUMP_ORDER, extractVersions, normalizeBump } from '../lib/versionCompare.js' +import { BUMP_ORDER, extractVersions, normalizeBump } from '../lib/utils/versionCompare.js' describe('versionCompare', () => { describe('BUMP_ORDER', () => { From 8cfda47010058c35ac8bb3603e21fe109f1dfaf6 Mon Sep 17 00:00:00 2001 From: Thomas Taylor Date: Sat, 28 Mar 2026 20:48:52 +0000 Subject: [PATCH 04/14] Breaking: Simplify UI installer and remove app boot from install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the install flow to: pick release → download → configure → enter email → done. The installer no longer boots the full application or registers users via the API. Instead it writes a conf/.superuser file with the email and a generated password for the app to process on first boot. Backend changes: - Remove /start, /registeruser, /prereq, /schemas/user endpoints - Add POST /superuser endpoint (writes conf/.superuser) - Remove startApp and registerSuperUser imports Frontend changes: - Replace DOM event orchestration (click-button, form-submit) with direct nextStep() callbacks - Remove checkpoint/resume dead code from fetchReleases - Remove startApp, createUser, saveCheckpoint, waitForForm, awaitButtonPress, validateUser methods - Add createSuperUser method and EmailInput/GeneratedPassword components - Simplify step configs (install: 7→5 steps, update: 4→3 steps) Cleanup: - Remove jQuery and Bootstrap JS (unused) - Switch to production React builds - Remove --pipe-passwd CLI option --- bin/install.js | 34 ++++++- lib/UiServer.js | 36 ++----- public/index.html | 10 +- public/js/Installer.js | 149 +++++++++++------------------ public/js/components.js | 73 +++++++++----- public/js/config/config-example.js | 62 ++++++------ public/js/config/install-dev.js | 60 +++++------- public/js/config/install.js | 61 ++++-------- public/js/config/update.js | 29 +++--- 9 files changed, 232 insertions(+), 282 deletions(-) diff --git a/bin/install.js b/bin/install.js index b9b10b8..1c0233c 100644 --- a/bin/install.js +++ b/bin/install.js @@ -1,8 +1,10 @@ +import { randomBytes } from 'crypto' +import fs from 'fs/promises' +import path from 'path' +import prompts from 'prompts' import CliCommand from '../lib/CliCommand.js' import DEFAULT_OPTIONS from '../lib/DEFAULT_OPTIONS.js' -import fs from 'fs/promises' import Installer from '../lib/Installer.js' -import registerSuperUser from '../lib/utils/registerSuperUser.js' import UiServer from '../lib/UiServer.js' export default class Install extends CliCommand { @@ -15,8 +17,7 @@ export default class Install extends CliCommand { getReleaseData: true, options: [ ...DEFAULT_OPTIONS, - ['-e --super-email ', 'The admin user email address'], - ['-p --pipe-passwd', 'Whether the admin password will be piped into the script'] + ['-e --super-email ', 'The admin user email address'] ] } } @@ -33,7 +34,7 @@ export default class Install extends CliCommand { console.log(`Installing Adapt authoring tool ${this.options.tag} in ${this.options.cwd}`) await new Installer(this.options).install() - await registerSuperUser(this.options) + await this.createSuperUser() this.logSuccess('Install completed successfully!') } catch (e) { @@ -41,6 +42,29 @@ export default class Install extends CliCommand { } } + async createSuperUser () { + let email = this.options.superEmail + if (!email) { + const { emailInput } = await prompts([{ + type: 'text', + name: 'emailInput', + message: 'Enter an email address for the super admin account' + }]) + email = emailInput + } + if (!email) throw new Error('Email is required for super admin account') + + const password = randomBytes(16).toString('base64url') + const confDir = path.resolve(this.options.cwd, 'conf') + await fs.mkdir(confDir, { recursive: true }) + await fs.writeFile(path.resolve(confDir, '.superuser'), JSON.stringify({ email, password }, null, 2)) + + console.log('\nSuper admin account will be created on first app start.') + console.log(`Email: ${email}`) + console.log(`Password: ${password}`) + console.log('Please save this password. You will be asked to change it on first login.\n') + } + async checkTargetDir () { let files try { diff --git a/lib/UiServer.js b/lib/UiServer.js index 8fe0e0c..1109414 100644 --- a/lib/UiServer.js +++ b/lib/UiServer.js @@ -3,6 +3,7 @@ import EventEmitter from 'events' import { fileURLToPath } from 'url' import fs from 'fs/promises' import http from 'http' +import path from 'path' import { randomBytes } from 'crypto' import { spawn } from 'child_process' import Installer from './Installer.js' @@ -13,9 +14,7 @@ import getStartCommands from './utils/getStartCommands.js' import installLocalModules from './utils/installLocalModules.js' import parseBody from './utils/parseBody.js' import parseQuery from './utils/parseQuery.js' -import registerSuperUser from './utils/registerSuperUser.js' import saveConfig from './utils/saveConfig.js' -import startApp from './utils/startApp.js' export default class UiServer extends EventEmitter { constructor (options) { @@ -29,13 +28,10 @@ export default class UiServer extends EventEmitter { if (this.options.action === 'install') { this.get('/schemas/config', this.schemasHandler.bind(this)) - this.get('/schemas/user', this.schemasHandler.bind(this)) this.post('/download', this.downloadHandler.bind(this)) - this.post('/prereq', this.prereqHandler.bind(this)) this.get('/secrets', this.generateSecrets.bind(this)) - this.post('/registeruser', this.registerUserHandler.bind(this)) this.post('/save', this.saveConfigHandler.bind(this)) - this.post('/start', this.startAppHandler.bind(this)) + this.post('/superuser', this.superUserHandler.bind(this)) } if (this.options.devMode) { this.get('/modules', this.getModulesHandler.bind(this)) @@ -143,16 +139,6 @@ export default class UiServer extends EventEmitter { res.json(this.schemas[req.url.replace('/schemas/', '')]) } - async registerUserHandler (req, res) { - try { - await registerSuperUser({ ...this.options, superEmail: req.body.email, superPassword: req.body.password }) - res.send(undefined, 201) - } catch (e) { - const app = await startApp(this.options) - res.send(e.constructor.name === 'AdaptError' ? app.lang.translate('en', e) : e.message, e.statusCode) - } - } - async saveConfigHandler (req, res) { await saveConfig(this.options.cwd, req.body) res.json({ rootDir: this.options.cwd }) @@ -172,12 +158,6 @@ export default class UiServer extends EventEmitter { res.end() } - async prereqHandler (req, res) { - const checkPrerequisites = (await import('./utils/checkPrerequisites.js')).default - await checkPrerequisites(this.options) - res.send() - } - async generateSecrets (req, res) { const setSecretsRecursive = async (schema, data = {}) => { await Promise.all(Object.entries(schema.properties).map(async ([k, v]) => { @@ -197,10 +177,14 @@ export default class UiServer extends EventEmitter { return res.json(data) } - async startAppHandler (req, res) { - const app = await startApp(this.options) - const ui = await app.waitForModule('ui') - ui.postBuildHook.tap(() => res.send()) + async superUserHandler (req, res) { + const { email } = req.body + if (!email) return res.send('Email is required', 400) + const password = randomBytes(16).toString('base64url') + const confDir = path.resolve(this.options.cwd, 'conf') + await fs.mkdir(confDir, { recursive: true }) + await fs.writeFile(path.resolve(confDir, '.superuser'), JSON.stringify({ email, password }, null, 2)) + res.json({ password }) } async getReleasesHandler (req, res) { diff --git a/public/index.html b/public/index.html index 4df4015..0d2d93b 100644 --- a/public/index.html +++ b/public/index.html @@ -15,12 +15,8 @@ - - - - - - + + @@ -39,4 +35,4 @@ - \ No newline at end of file + diff --git a/public/js/Installer.js b/public/js/Installer.js index 2a66151..950bd88 100644 --- a/public/js/Installer.js +++ b/public/js/Installer.js @@ -9,36 +9,36 @@ class Installer extends React.Component { if(!config.steps.length) throw new Error('No installer steps defined!'); } catch(e) { return this.onError(e); - } + } config.steps = [ { - title: `Checking releases`, + title: 'Checking releases', breadcrumb: false, icon: 'lnr-hourglass', showLoadingBar: true, - actions: [this.fetchReleases], - haltOnComplete: true + actions: [this.fetchReleases] }, { - title: `No releases found`, + title: 'No releases found', breadcrumb: false, icon: `lnr-thumbs-${config.action === 'update' ? 'up' : 'down'}`, content: () =>

Sorry, no releases were found at this time.

You can try using the --prerelease flag to include pre-release versions (WARNING: may contain bugs).

, - actions: [() => this.exit('No releases found')], button: 'Exit', + onButton: () => this.exit('No releases found') }, ...config.steps ]; - this.state = { + this.state = { config: {}, showAdvanced: false, step: 0, ...config }; } + async componentDidMount() { try { await this.performStep(); @@ -46,37 +46,45 @@ class Installer extends React.Component { this.onError(e); } } + render() { return (
this.exit('User cancelled the install')}/>
- {this.state.steps.map((s,i) => )} + {this.state.steps.map((s,i) => this.onStepButton(s)} />)}
); } + + onStepButton(step) { + if(step.onButton) { + step.onButton(); + } else { + this.nextStep(); + } + } + async performStep(step = this.state.steps[this.state.step]) { if(!step) return this.exit(); - if(step.button) await this.awaitButtonPress(); - if(step.actions) for (const a of step.actions) await a.call(this); - if(step.actions && this.state.action === 'install' && this.state.step > 1) { - await this.saveCheckpoint(); - } - if(!step.haltOnComplete) { - this.setState({ step: this.state.step+1 }); - await this.performStep(); - } + if(step.button || step.waitForUser) return; + await this.runActions(step); + if(!step.haltOnComplete) this.advance(); } - async awaitButtonPress(eventName = 'click-button') { - return new Promise(resolve => { - const resolver = () => { - document.removeEventListener(eventName, resolver); - resolve(); - }; - document.addEventListener(eventName, resolver); - }); + async nextStep() { + await this.runActions(this.state.steps[this.state.step]); + this.advance(); + } + + advance() { + this.setState({ step: this.state.step + 1 }, () => this.performStep()); + } + + async runActions(step) { + if(!step?.actions) return; + for(const a of step.actions) await a.call(this); } /** @@ -84,17 +92,16 @@ class Installer extends React.Component { */ post(url, data = {}, options = {}) { - return this.fetch(url, 'POST', { + return this.apiRequest(url, 'POST', { headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }, options); } - async fetch(url, method = 'GET', options = {}) { + async apiRequest(url, method = 'GET', options = {}) { const res = await fetch(url, { ...options, method }); if(options.handleErrors !== false && res.status > 299) { - const message = await res.text() ?? res.statusText; - throw new Error(message); + throw new Error(await res.text() ?? res.statusText); } return res; } @@ -107,60 +114,33 @@ class Installer extends React.Component { * API calls */ - async createUser(userData) { - const { email, password } = userData; - const res = await this.post('/registeruser', { email, password }, { handleErrors: false }); - if(res.status === 400) return this.setState({ validationErrors: { superUser: { __errors: [await res.text()] } } }); - if(res.status > 299) throw new Error(await res.text()); - } - async download() { - await this.post('/prereq'); await this.post(`/download?tag=${this.state.selectedRelease}`); await this.fetchSchemas(); await this.generateSecrets(); } async getModules() { - const dependencies = Object.keys(await (await this.fetch('/modules')).json()); + const dependencies = Object.keys(await (await this.apiRequest('/modules')).json()); this.setState({ dependencies }); } - + async downloadModules() { - if(!this.state?.dependenciesChecked?.length) { - return; - } + if(!this.state?.dependenciesChecked?.length) return; return this.post('/installmodules', this.state.dependenciesChecked); } async fetchReleases() { - const { currentVersion, releases } = await (await this.fetch('/releases')).json(); + const { currentVersion, releases } = await (await this.apiRequest('/releases')).json(); const latestRelease = releases.find(r => r.tag_name)?.tag_name; - - let checkpoint = null; - if(this.state.action === 'install') { - try { - const res = await this.fetch('/checkpoint', 'GET', { handleErrors: false }); - if(res.status === 200) checkpoint = await res.json(); - } catch(e) {} - } - this.setState({ currentRelease: currentVersion, newRelease: latestRelease, - selectedRelease: checkpoint?.selectedRelease || latestRelease, + selectedRelease: latestRelease, releases }); - if(!releases.length) { this.setState({ step: 1 }); - } else if(checkpoint && checkpoint.step >= 2) { - const resumeStep = checkpoint.step + 1; - this.setState({ step: resumeStep }); - if(resumeStep > this.state.downloadStep) { - await this.fetchSchemas(); - await this.generateSecrets(); - } } else { this.setState({ step: 2 }); } @@ -168,54 +148,40 @@ class Installer extends React.Component { } async fetchSchemas() { - const configSchemas = Object.values(await (await this.fetch(`/schemas/config`)).json()); - this.setState({ - configSchema: { properties: configSchemas.reduce((m,s) => Object.assign(m, { [s.name]: { title: s.name, ...s.schema } }), {}) }, - userSchema: await (await this.fetch(`/schemas/user`)).json() + const configSchemas = Object.values(await (await this.apiRequest('/schemas/config')).json()); + this.setState({ + configSchema: { properties: configSchemas.reduce((m,s) => Object.assign(m, { [s.name]: { title: s.name, ...s.schema } }), {}) } }); } - async generateSecrets() { - this.setState({ config: { ...this.state.config, ...(await (await this.fetch('/secrets')).json()) } }); + async generateSecrets() { + this.setState({ config: { ...this.state.config, ...(await (await this.apiRequest('/secrets')).json()) } }); } - async waitForForm() { - return new Promise(resolve => document.addEventListener('form-submit', () => resolve())); - } - - async cacheConfig({ formData }) { - this.setState({ config: formData }); - } - async saveConfig({ formData }) { const res = await this.post('/save', formData); this.setState({ rootDir: (await res.json()).rootDir }); } - async saveCheckpoint() { - await this.post('/checkpoint', { - step: this.state.step, - selectedRelease: this.state.selectedRelease - }); + async createSuperUser() { + const res = await this.post('/superuser', { email: this.state.superUserEmail }); + const { password } = await res.json(); + this.setState({ generatedPassword: password }); } async update() { await this.post(`/update?version=${this.state.selectedRelease}`); } - - async startApp() { - await this.post('/start'); - } - + async getCwd() { - this.setState({ cmds: (await (await this.fetch('/commands')).json()) }); + this.setState({ cmds: (await (await this.apiRequest('/commands')).json()) }); } async exit(errorMsg) { await this.post('/exit', errorMsg); return window.close(); } - + /** * UI actions */ @@ -224,7 +190,7 @@ class Installer extends React.Component { let deps = this.state.dependenciesChecked || []; if(name === "all") { deps = this.state.dependencies; - document.dispatchEvent(new Event('click-button')); + this.nextStep(); } else if(checked) { deps.push(name); } else { @@ -233,11 +199,4 @@ class Installer extends React.Component { } this.setState({ dependenciesChecked: deps }); } - - validateUser({ superUser: { password, confirmPassword } }, errors) { - if (password !== confirmPassword) { - errors.superUser.confirmPassword.addError("Passwords don't match"); - } - return errors; - } } diff --git a/public/js/components.js b/public/js/components.js index a34fa0b..7463eaa 100644 --- a/public/js/components.js +++ b/public/js/components.js @@ -18,9 +18,7 @@ function AdaptDependencies(props) { } function AppStartInstructions(props) { - if(!props.cmds) { - return ''; - } + if(!props.cmds) return ''; const { windows, bash } = props.cmds; return

To start the application, run the following commands in your favourite terminal application:

@@ -50,7 +48,7 @@ function Breadcrumbs(props) { function Checkbox(props) { return
@@ -61,7 +59,7 @@ function ConfigForm(props) { return
Tip: any settings which aren't required or have default values have been hidden. These can be revealed by selecting the checkbox below (not recommended for beginners).
component.setState({ showAdvanced: !component.state.showAdvanced })}/> -
+ component.setState({ config: d.formData })} onSubmit={async d => { await component.saveConfig(d); component.nextStep(); }}/>
; } @@ -69,6 +67,24 @@ function DocsLink() { return

Head over to the Project documentation for guides and API docs.

; } +function EmailInput({ component }) { + return
+

Enter the email address for your super admin account. A password will be generated automatically.

+
+ + component.setState({ superUserEmail: e.target.value })} + /> +
+ +
; +} + function ErrorDisplay(e) { console.error(e); const message = e.message ? e.message : e.toString ? e.toString() : e; @@ -80,7 +96,7 @@ function ErrorDisplay(e) {

Something went wrong

An error occurred, see below for more information.

- {errorLines.map((s,i) => {s}{i < errorLines.length-1 ?
: ''}
)} + {errorLines.map((s,i) => {s}{i < errorLines.length-1 ?
: ''}
)}

You can safely close this window.

@@ -97,7 +113,7 @@ class Form extends React.Component { }); }); return { ...this.props.schema, required: Object.keys(this.props.schema.properties) }; - } + } const requiredSchema = { type: 'object', properties: {} }; Object.entries(this.props.schema.properties).reduce((m,[k,v]) => { if(v.required) { @@ -116,16 +132,15 @@ class Form extends React.Component { } render() { if(!this.props.schema) return null; - const validate = this.props.validate || undefined; try { - return this.props.onChange(...args) : () => {}} - onSubmit={(...args) => document.dispatchEvent(new Event('form-submit')) && this.props.onSubmit(...args)} + return {})} + onSubmit={this.props.onSubmit} onError={this.onError} /> } catch(e) { console.error(e); @@ -137,19 +152,28 @@ class Form extends React.Component { } } +function GeneratedPassword({ password }) { + if(!password) return null; + return
+

Your super admin password:

+
{password}
+

Please save this password. You will be asked to change it on first login.

+
; +} + function Instruction(props) { return

{props.text}

; } function NavButton(props) { - return ; } function ReleaseSelect({ component }) { const releases = component.state?.releases || []; - const selected = component.state?.latestRelease; + const selected = component.state?.selectedRelease; return