diff --git a/Dockerfile b/Dockerfile index 0d2f959..a5d1263 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,61 +1,55 @@ ################## First Stage - Creating base ######################### # Created a variable to hold our node base image -ARG NODE_IMAGE=node:22-trixie-slim +ARG NODE_IMAGE=node:22-bookworm-slim FROM $NODE_IMAGE AS base - # Install dumb-init and ClamAV, and perform ClamAV database update -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - dumb-init \ - clamav \ - clamav-daemon \ - ca-certificates \ +RUN apt update \ + && apt-get install -y dumb-init clamav clamav-daemon nano \ && rm -rf /var/lib/apt/lists/* \ # Creating folders and changing ownerships - && mkdir -p /home/node/app \ + && mkdir -p /home/node/app && chown node:node /home/node/app \ && mkdir -p /var/lib/clamav \ && mkdir /usr/local/share/clamav \ + && chown -R node:clamav /var/lib/clamav /usr/local/share/clamav /etc/clamav \ + # permissions && mkdir /var/run/clamav \ - && mkdir -p /var/log/clamav \ - && mkdir -p /tmp/clamav-logs \ - - # Set ownership and permissions - && chown node:node /home/node/app \ - # && chown -R node:clamav /var/lib/clamav /usr/local/share/clamav /etc/clamav /var/run/clamav \ - && chown -R clamav:clamav /var/lib/clamav /usr/local/share/clamav /etc/clamav /var/run/clamav /var/log/clamav \ - && chmod 755 /tmp/clamav-logs \ - && chmod 750 /var/run/clamav \ - && chmod 755 /var/lib/clamav \ - && chmod 755 /var/log/clamav \ - # Add node user to clamav group and allow sudo for clamav commands - && usermod -a -G clamav node \ - && chmod g+w /var/run/clamav /var/lib/clamav /var/log/clamav /tmp/clamav-logs + && chown node:clamav /var/run/clamav \ + && chmod 750 /var/run/clamav +# ----------------------------------------------- +# --- ClamAV & FeshClam ------------------------- +# ----------------------------------------------- +# RUN \ +# chmod 644 /etc/clamav/freshclam.conf && \ +# freshclam && \ +# mkdir /var/run/clamav && \ + # chown -R clamav:root /var/run/clamav +# # initial update of av databases +# RUN freshclam -# Configure ClamAV - copy config files before switching user -# COPY --chown=node:clamav ./*.conf /etc/clamav/ -COPY --chown=clamav:clamav ./*.conf /etc/clamav/ - -# Copy entrypoint script -COPY --chown=node:node docker-entrypoint.sh /home/node/app/docker-entrypoint.sh -RUN chmod +x /home/node/app/docker-entrypoint.sh - -ENV TZ="Europe/Vienna" +# Configure Clam AV... +COPY --chown=node:clamav ./*.conf /etc/clamav/ +# # permissions +# RUN mkdir /var/run/clamav && \ +# chown node:clamav /var/run/clamav && \ +# chmod 750 /var/run/clamav # Setting the working directory WORKDIR /home/node/app # Changing the current active user to "node" - -# Download initial ClamAV database as root before switching users -USER root -RUN freshclam --quiet || echo "Initial database download failed - will retry at runtime" - USER node -# Initial update of AV databases (moved after USER directive) -# RUN freshclam || true +# initial update of av databases +RUN freshclam + +# VOLUME /var/lib/clamav +COPY --chown=node:clamav docker-entrypoint.sh /home/node/app/docker-entrypoint.sh +RUN chmod +x /home/node/app/docker-entrypoint.sh +ENV TZ="Europe/Vienna" + + ################## Second Stage - Installing dependencies ########## @@ -76,13 +70,14 @@ ENV NODE_ENV=production # We run "node ace build" to build the app (dist folder) for production RUN node ace build --ignore-ts-errors # RUN node ace build --production +# RUN node ace build --ignore-ts-errors ################## Final Stage - Production ######################### # In this final stage, we will start running the application FROM base AS production # Here, we include all the required environment variables -ENV NODE_ENV=production +# ENV NODE_ENV=production # ENV PORT=$PORT # ENV HOST=0.0.0.0 @@ -96,4 +91,4 @@ COPY --chown=node:node --from=build /home/node/app/build . EXPOSE 3333 ENTRYPOINT ["/home/node/app/docker-entrypoint.sh"] # Run the command to start the server using "dumb-init" -CMD [ "node", "bin/server.js" ] \ No newline at end of file +CMD [ "dumb-init", "node", "bin/server.js" ] \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 23bb390..0000000 --- a/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ - -MIT License - -Copyright (c) 2025 Tethys Research Repository - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE \ No newline at end of file diff --git a/adonisrc.ts b/adonisrc.ts index e42693a..de94c63 100644 --- a/adonisrc.ts +++ b/adonisrc.ts @@ -30,9 +30,9 @@ export default defineConfig({ () => import('#start/rules/unique'), () => import('#start/rules/translated_language'), () => import('#start/rules/unique_person'), - // () => import('#start/rules/file_length'), - // () => import('#start/rules/file_scan'), - // () => import('#start/rules/allowed_extensions_mimetypes'), + () => import('#start/rules/file_length'), + () => import('#start/rules/file_scan'), + () => import('#start/rules/allowed_extensions_mimetypes'), () => import('#start/rules/dependent_array_min_length'), () => import('#start/rules/referenceValidation'), () => import('#start/rules/valid_mimetype'), diff --git a/app/Controllers/Http/Api/DatasetController.ts b/app/Controllers/Http/Api/DatasetController.ts index 0e38e34..f6bc648 100644 --- a/app/Controllers/Http/Api/DatasetController.ts +++ b/app/Controllers/Http/Api/DatasetController.ts @@ -1,35 +1,23 @@ import type { HttpContext } from '@adonisjs/core/http'; +// import Person from 'App/Models/Person'; import Dataset from '#models/dataset'; import { StatusCodes } from 'http-status-codes'; // node ace make:controller Author export default class DatasetController { - /** - * GET /api/datasets - * Find all published datasets - */ - public async index({ response }: HttpContext) { - try { - const datasets = await Dataset.query() - .where(function (query) { - query.where('server_state', 'published').orWhere('server_state', 'deleted'); - }) - .preload('titles') - .preload('identifier') - .orderBy('server_date_published', 'desc'); + public async index({}: HttpContext) { + // Select datasets with server_state 'published' or 'deleted' and sort by the last published date + const datasets = await Dataset.query() + .where(function (query) { + query.where('server_state', 'published').orWhere('server_state', 'deleted'); + }) + .preload('titles') + .preload('identifier') + .orderBy('server_date_published', 'desc'); - return response.status(StatusCodes.OK).json(datasets); - } catch (error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - message: error.message || 'Some error occurred while retrieving datasets.', - }); - } + return datasets; } - /** - * GET /api/dataset - * Find all published datasets - */ public async findAll({ response }: HttpContext) { try { const datasets = await Dataset.query() @@ -45,142 +33,48 @@ export default class DatasetController { } } - /** - * GET /api/dataset/:publish_id - * Find one dataset by publish_id - */ - public async findOne({ response, params }: HttpContext) { - try { - const dataset = await Dataset.query() - .where('publish_id', params.publish_id) - .preload('titles') - .preload('descriptions') // Using 'descriptions' instead of 'abstracts' - .preload('user', (builder) => { - builder.select(['id', 'firstName', 'lastName', 'avatar', 'login']); - }) - .preload('authors', (builder) => { - builder - .select(['id', 'academic_title', 'first_name', 'last_name', 'identifier_orcid', 'status', 'name_type']) - .withCount('datasets', (query) => { - query.as('datasets_count'); - }) - .pivotColumns(['role', 'sort_order']) - .orderBy('pivot_sort_order', 'asc'); - }) - .preload('contributors', (builder) => { - builder - .select(['id', 'academic_title', 'first_name', 'last_name', 'identifier_orcid', 'status', 'name_type']) - .withCount('datasets', (query) => { - query.as('datasets_count'); - }) - .pivotColumns(['role', 'sort_order', 'contributor_type']) - .orderBy('pivot_sort_order', 'asc'); - }) - .preload('subjects') - .preload('coverage') - .preload('licenses') - .preload('references') - .preload('project') - .preload('referenced_by', (builder) => { - builder.preload('dataset', (builder) => { - builder.preload('identifier'); - }); - }) - .preload('files', (builder) => { - builder.preload('hashvalues'); - }) - .preload('identifier') - .first(); // Use first() instead of firstOrFail() to handle not found gracefully - - if (!dataset) { - return response.status(StatusCodes.NOT_FOUND).json({ - message: `Cannot find Dataset with publish_id=${params.publish_id}.`, + public async findOne({ params }: HttpContext) { + const datasets = await Dataset.query() + .where('publish_id', params.publish_id) + .preload('titles') + .preload('descriptions') + .preload('user', (builder) => { + builder.select(['id', 'firstName', 'lastName', 'avatar', 'login']); + }) + .preload('authors', (builder) => { + builder + .select(['id', 'academic_title', 'first_name', 'last_name', 'identifier_orcid', 'status', 'name_type']) + .withCount('datasets', (query) => { + query.as('datasets_count'); + }) + .pivotColumns(['role', 'sort_order']) + .orderBy('pivot_sort_order', 'asc'); + }) + .preload('contributors', (builder) => { + builder + .select(['id', 'academic_title', 'first_name', 'last_name', 'identifier_orcid', 'status', 'name_type']) + .withCount('datasets', (query) => { + query.as('datasets_count'); + }) + .pivotColumns(['role', 'sort_order', 'contributor_type']) + .orderBy('pivot_sort_order', 'asc'); + }) + .preload('subjects') + .preload('coverage') + .preload('licenses') + .preload('references') + .preload('project') + .preload('referenced_by', (builder) => { + builder.preload('dataset', (builder) => { + builder.preload('identifier'); }); - } + }) + .preload('files', (builder) => { + builder.preload('hashvalues'); + }) + .preload('identifier') + .firstOrFail(); - return response.status(StatusCodes.OK).json(dataset); - } catch (error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - message: error.message || `Error retrieving Dataset with publish_id=${params.publish_id}.`, - }); - } - } - - /** - * GET /:prefix/:value - * Find dataset by identifier (e.g., https://doi.tethys.at/10.24341/tethys.99.2) - */ - public async findByIdentifier({ response, params }: HttpContext) { - const identifierValue = `${params.prefix}/${params.value}`; - - // Optional: Validate DOI format - if (!identifierValue.match(/^10\.\d+\/[a-zA-Z0-9._-]+\.[0-9]+(?:\.[0-9]+)*$/)) { - return response.status(StatusCodes.BAD_REQUEST).json({ - message: `Invalid DOI format: ${identifierValue}`, - }); - } - - try { - // Method 1: Using subquery with whereIn (most similar to your original) - const dataset = await Dataset.query() - // .whereIn('id', (subQuery) => { - // subQuery.select('dataset_id').from('dataset_identifiers').where('value', identifierValue); - // }) - .whereHas('identifier', (builder) => { - builder.where('value', identifierValue); - }) - .preload('titles') - .preload('descriptions') // Using 'descriptions' instead of 'abstracts' - .preload('user', (builder) => { - builder.select(['id', 'firstName', 'lastName', 'avatar', 'login']); - }) - .preload('authors', (builder) => { - builder - .select(['id', 'academic_title', 'first_name', 'last_name', 'identifier_orcid', 'status', 'name_type']) - .withCount('datasets', (query) => { - query.as('datasets_count'); - }) - .pivotColumns(['role', 'sort_order']) - .wherePivot('role', 'author') - .orderBy('pivot_sort_order', 'asc'); - }) - .preload('contributors', (builder) => { - builder - .select(['id', 'academic_title', 'first_name', 'last_name', 'identifier_orcid', 'status', 'name_type']) - .withCount('datasets', (query) => { - query.as('datasets_count'); - }) - .pivotColumns(['role', 'sort_order', 'contributor_type']) - .wherePivot('role', 'contributor') - .orderBy('pivot_sort_order', 'asc'); - }) - .preload('subjects') - .preload('coverage') - .preload('licenses') - .preload('references') - .preload('project') - .preload('referenced_by', (builder) => { - builder.preload('dataset', (builder) => { - builder.preload('identifier'); - }); - }) - .preload('files', (builder) => { - builder.preload('hashvalues'); - }) - .preload('identifier') - .first(); - - if (!dataset) { - return response.status(StatusCodes.NOT_FOUND).json({ - message: `Cannot find Dataset with identifier=${identifierValue}.`, - }); - } - - return response.status(StatusCodes.OK).json(dataset); - } catch (error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - message: error.message || `Error retrieving Dataset with identifier=${identifierValue}.`, - }); - } + return datasets; } } diff --git a/app/Controllers/Http/Submitter/DatasetController.ts b/app/Controllers/Http/Submitter/DatasetController.ts index a308634..b7bb7a0 100644 --- a/app/Controllers/Http/Submitter/DatasetController.ts +++ b/app/Controllers/Http/Submitter/DatasetController.ts @@ -235,7 +235,6 @@ export default class DatasetController { .isUniquePerson({ table: 'persons', column: 'email', idField: 'id' }), first_name: vine.string().trim().minLength(3).maxLength(255).optional().requiredWhen('name_type', '=', 'Personal'), last_name: vine.string().trim().minLength(3).maxLength(255), - identifier_orcid: vine.string().trim().maxLength(255).orcid().optional(), }), ) .minLength(1) @@ -252,7 +251,6 @@ export default class DatasetController { .isUniquePerson({ table: 'persons', column: 'email', idField: 'id' }), first_name: vine.string().trim().minLength(3).maxLength(255).optional().requiredWhen('name_type', '=', 'Personal'), last_name: vine.string().trim().minLength(3).maxLength(255), - identifier_orcid: vine.string().trim().maxLength(255).orcid().optional(), pivot_contributor_type: vine.enum(Object.keys(ContributorTypes)), }), ) @@ -328,7 +326,6 @@ export default class DatasetController { .isUniquePerson({ table: 'persons', column: 'email', idField: 'id' }), first_name: vine.string().trim().minLength(3).maxLength(255).optional().requiredWhen('name_type', '=', 'Personal'), last_name: vine.string().trim().minLength(3).maxLength(255), - identifier_orcid: vine.string().trim().maxLength(255).orcid().optional(), }), ) .minLength(1) @@ -345,7 +342,6 @@ export default class DatasetController { .isUniquePerson({ table: 'persons', column: 'email', idField: 'id' }), first_name: vine.string().trim().minLength(3).maxLength(255).optional().requiredWhen('name_type', '=', 'Personal'), last_name: vine.string().trim().minLength(3).maxLength(255), - identifier_orcid: vine.string().trim().maxLength(255).orcid().optional(), pivot_contributor_type: vine.enum(Object.keys(ContributorTypes)), }), ) diff --git a/app/Library/Doi/DoiClient.ts b/app/Library/Doi/DoiClient.ts index 4232ac4..86151e7 100644 --- a/app/Library/Doi/DoiClient.ts +++ b/app/Library/Doi/DoiClient.ts @@ -1,3 +1,6 @@ +// import { Client } from 'guzzle'; +// import { Log } from '@adonisjs/core/build/standalone'; +// import { DoiInterface } from './interfaces/DoiInterface'; import DoiClientContract from '#app/Library/Doi/DoiClientContract'; import DoiClientException from '#app/exceptions/DoiClientException'; import { StatusCodes } from 'http-status-codes'; @@ -9,14 +12,14 @@ export class DoiClient implements DoiClientContract { public username: string; public password: string; public serviceUrl: string; - public apiUrl: string; constructor() { // const datacite_environment = process.env.DATACITE_ENVIRONMENT || 'debug'; this.username = process.env.DATACITE_USERNAME || ''; this.password = process.env.DATACITE_PASSWORD || ''; this.serviceUrl = process.env.DATACITE_SERVICE_URL || ''; - this.apiUrl = process.env.DATACITE_API_URL || 'https://api.datacite.org'; + // this.prefix = process.env.DATACITE_PREFIX || ''; + // this.base_domain = process.env.BASE_DOMAIN || ''; if (this.username === '' || this.password === '' || this.serviceUrl === '') { const message = 'issing configuration settings to properly initialize DOI client'; @@ -87,240 +90,4 @@ export class DoiClient implements DoiClientContract { throw new DoiClientException(error.response.status, error.response.data); } } - - /** - * Retrieves DOI information from DataCite REST API - * - * @param doiValue The DOI identifier e.g. '10.5072/tethys.999' - * @returns Promise with DOI information or null if not found - */ - public async getDoiInfo(doiValue: string): Promise { - try { - // Use configurable DataCite REST API URL - const dataciteApiUrl = `${this.apiUrl}/dois/${doiValue}`; - const response = await axios.get(dataciteApiUrl, { - headers: { - Accept: 'application/vnd.api+json', - }, - }); - - if (response.status === 200 && response.data.data) { - return { - created: response.data.data.attributes.created, - registered: response.data.data.attributes.registered, - updated: response.data.data.attributes.updated, - published: response.data.data.attributes.published, - state: response.data.data.attributes.state, - url: response.data.data.attributes.url, - metadata: response.data.data.attributes, - }; - } - } catch (error) { - if (error.response?.status === 404) { - logger.debug(`DOI ${doiValue} not found in DataCite`); - return null; - } - - logger.debug(`DataCite REST API failed for ${doiValue}: ${error.message}`); - - // Fallback to MDS API - return await this.getDoiInfoFromMds(doiValue); - } - - return null; - } - - /** - * Fallback method to get DOI info from MDS API - * - * @param doiValue The DOI identifier - * @returns Promise with basic DOI information or null - */ - private async getDoiInfoFromMds(doiValue: string): Promise { - try { - const auth = { - username: this.username, - password: this.password, - }; - - // Get DOI URL - const doiResponse = await axios.get(`${this.serviceUrl}/doi/${doiValue}`, { auth }); - - if (doiResponse.status === 200) { - // Get metadata if available - try { - const metadataResponse = await axios.get(`${this.serviceUrl}/metadata/${doiValue}`, { - auth, - headers: { - Accept: 'application/xml', - }, - }); - - return { - url: doiResponse.data.trim(), - metadata: metadataResponse.data, - created: new Date().toISOString(), // MDS doesn't provide creation dates - registered: new Date().toISOString(), // Use current time as fallback - source: 'mds', - }; - } catch (metadataError) { - // Return basic info even if metadata fetch fails - return { - url: doiResponse.data.trim(), - created: new Date().toISOString(), - registered: new Date().toISOString(), - source: 'mds', - }; - } - } - } catch (error) { - if (error.response?.status === 404) { - logger.debug(`DOI ${doiValue} not found in DataCite MDS`); - return null; - } - - logger.debug(`DataCite MDS API failed for ${doiValue}: ${error.message}`); - } - - return null; - } - - /** - * Checks if a DOI exists in DataCite - * - * @param doiValue The DOI identifier - * @returns Promise True if DOI exists - */ - public async doiExists(doiValue: string): Promise { - const doiInfo = await this.getDoiInfo(doiValue); - return doiInfo !== null; - } - - /** - * Gets the last modification date of a DOI - * - * @param doiValue The DOI identifier - * @returns Promise Last modification date or creation date if never updated, null if not found - */ - public async getDoiLastModified(doiValue: string): Promise { - const doiInfo = await this.getDoiInfo(doiValue); - - if (doiInfo) { - // Use updated date if available, otherwise fall back to created/registered date - const dateToUse = doiInfo.updated || doiInfo.registered || doiInfo.created; - - if (dateToUse) { - logger.debug( - `DOI ${doiValue}: Using ${doiInfo.updated ? 'updated' : doiInfo.registered ? 'registered' : 'created'} date: ${dateToUse}`, - ); - return new Date(dateToUse); - } - } - - return null; - } - - /** - * Makes a DOI unfindable (registered but not discoverable) - * Note: DOIs cannot be deleted, only made unfindable - * await doiClient.makeDoiUnfindable('10.21388/tethys.231'); - * - * @param doiValue The DOI identifier e.g. '10.5072/tethys.999' - * @returns Promise> The http response - */ - public async makeDoiUnfindable(doiValue: string): Promise> { - const auth = { - username: this.username, - password: this.password, - }; - - try { - // First, check if DOI exists - const exists = await this.doiExists(doiValue); - if (!exists) { - throw new DoiClientException(404, `DOI ${doiValue} not found`); - } - - // Delete the DOI URL mapping to make it unfindable - // This removes the URL but keeps the metadata registered - const response = await axios.delete(`${this.serviceUrl}/doi/${doiValue}`, { auth }); - - // Response Codes for DELETE /doi/{doi} - // 200 OK: operation successful - // 401 Unauthorized: no login - // 403 Forbidden: login problem, quota exceeded - // 404 Not Found: DOI does not exist - if (response.status !== 200) { - const message = `Unexpected DataCite MDS response code ${response.status}`; - logger.error(message); - throw new DoiClientException(response.status, message); - } - - logger.info(`DOI ${doiValue} successfully made unfindable`); - return response; - } catch (error) { - logger.error(`Failed to make DOI ${doiValue} unfindable: ${error.message}`); - if (error instanceof DoiClientException) { - throw error; - } - throw new DoiClientException(error.response?.status || 500, error.response?.data || error.message); - } - } - - /** - * Makes a DOI findable again by re-registering the URL - * await doiClient.makeDoiFindable( - * '10.21388/tethys.231', - * 'https://doi.dev.tethys.at/10.21388/tethys.231' - * ); - * - * @param doiValue The DOI identifier e.g. '10.5072/tethys.999' - * @param landingPageUrl The landing page URL - * @returns Promise> The http response - */ - public async makeDoiFindable(doiValue: string, landingPageUrl: string): Promise> { - const auth = { - username: this.username, - password: this.password, - }; - - try { - // Re-register the DOI with its URL to make it findable again - const response = await axios.put(`${this.serviceUrl}/doi/${doiValue}`, `doi=${doiValue}\nurl=${landingPageUrl}`, { auth }); - - // Response Codes for PUT /doi/{doi} - // 201 Created: operation successful - // 400 Bad Request: request body must be exactly two lines: DOI and URL - // 401 Unauthorized: no login - // 403 Forbidden: login problem, quota exceeded - // 412 Precondition failed: metadata must be uploaded first - if (response.status !== 201) { - const message = `Unexpected DataCite MDS response code ${response.status}`; - logger.error(message); - throw new DoiClientException(response.status, message); - } - - logger.info(`DOI ${doiValue} successfully made findable again`); - return response; - } catch (error) { - logger.error(`Failed to make DOI ${doiValue} findable: ${error.message}`); - if (error instanceof DoiClientException) { - throw error; - } - throw new DoiClientException(error.response?.status || 500, error.response?.data || error.message); - } - } - - /** - * Gets the current state of a DOI (draft, registered, findable) - * const state = await doiClient.getDoiState('10.21388/tethys.231'); - * console.log(`Current state: ${state}`); // 'findable' - * - * @param doiValue The DOI identifier - * @returns Promise The DOI state or null if not found - */ - public async getDoiState(doiValue: string): Promise { - const doiInfo = await this.getDoiInfo(doiValue); - return doiInfo?.state || null; - } } diff --git a/commands/fix_dataset_cross_references.ts b/commands/fix_dataset_cross_references.ts deleted file mode 100644 index 248fefd..0000000 --- a/commands/fix_dataset_cross_references.ts +++ /dev/null @@ -1,380 +0,0 @@ -/* -|-------------------------------------------------------------------------- -| node ace make:command fix-dataset-cross-references -| DONE: create commands/fix_dataset_cross_references.ts -|-------------------------------------------------------------------------- -*/ -import { BaseCommand, flags } from '@adonisjs/core/ace'; -import type { CommandOptions } from '@adonisjs/core/types/ace'; -import { DateTime } from 'luxon'; -import Dataset from '#models/dataset'; -import DatasetReference from '#models/dataset_reference'; -// import env from '#start/env'; - -interface MissingCrossReference { - sourceDatasetId: number; - targetDatasetId: number; - sourcePublishId: number | null; - targetPublishId: number | null; - sourceDoi: string | null; - targetDoi: string | null; - referenceType: string; - relation: string; - doi: string | null; - reverseRelation: string; -} - -export default class DetectMissingCrossReferences extends BaseCommand { - static commandName = 'detect:missing-cross-references'; - static description = 'Detect missing bidirectional cross-references between versioned datasets'; - - public static needsApplication = true; - - @flags.boolean({ alias: 'f', description: 'Fix missing cross-references automatically' }) - public fix: boolean = false; - - @flags.boolean({ alias: 'v', description: 'Verbose output' }) - public verbose: boolean = false; - - @flags.number({ alias: 'p', description: 'Filter by specific publish_id (source or target dataset)' }) - public publish_id?: number; - - // example: node ace detect:missing-cross-references --verbose -p 227 //if you want to filter by specific publish_id with details - // example: node ace detect:missing-cross-references --verbose - // example: node ace detect:missing-cross-references --fix -p 227 //if you want to filter by specific publish_id and fix it - // example: node ace detect:missing-cross-references - - public static options: CommandOptions = { - startApp: true, - staysAlive: false, - }; - - // Define the allowed relations that we want to process - private readonly ALLOWED_RELATIONS = ['IsNewVersionOf', 'IsPreviousVersionOf', 'IsVariantFormOf', 'IsOriginalFormOf']; - - async run() { - this.logger.info('πŸ” Detecting missing cross-references...'); - this.logger.info(`πŸ“‹ Processing only these relations: ${this.ALLOWED_RELATIONS.join(', ')}`); - - if (this.publish_id) { - this.logger.info(`Filtering by publish_id: ${this.publish_id}`); - } - - try { - const missingReferences = await this.findMissingCrossReferences(); - - if (missingReferences.length === 0) { - const filterMsg = this.publish_id ? ` for publish_id ${this.publish_id}` : ''; - this.logger.success(`All cross-references are properly linked for the specified relations${filterMsg}!`); - return; - } - - const filterMsg = this.publish_id ? ` (filtered by publish_id ${this.publish_id})` : ''; - this.logger.warning(`Found ${missingReferences.length} missing cross-reference(s)${filterMsg}:`); - - // Show brief list if not verbose mode - if (!this.verbose) { - for (const missing of missingReferences) { - const sourceDoi = missing.sourceDoi ? ` DOI: ${missing.sourceDoi}` : ''; - const targetDoi = missing.targetDoi ? ` DOI: ${missing.targetDoi}` : ''; - - this.logger.info( - `Dataset ${missing.sourceDatasetId} (Publish ID: ${missing.sourcePublishId}${sourceDoi}) ${missing.relation} Dataset ${missing.targetDatasetId} (Publish ID: ${missing.targetPublishId}${targetDoi}) β†’ missing reverse: ${missing.reverseRelation}`, - ); - } - } else { - // Verbose mode - show detailed info - for (const missing of missingReferences) { - this.logger.info( - `Dataset ${missing.sourceDatasetId} references ${missing.targetDatasetId}, but reverse reference is missing`, - ); - this.logger.info(` - Reference type: ${missing.referenceType}`); - this.logger.info(` - Relation: ${missing.relation}`); - this.logger.info(` - DOI: ${missing.doi}`); - } - } - - if (this.fix) { - await this.fixMissingReferences(missingReferences); - this.logger.success('All missing cross-references have been fixed!'); - } else { - if (this.verbose) { - this.printMissingReferencesList(missingReferences); - } - this.logger.info('πŸ’‘ Run with --fix flag to automatically create missing cross-references'); - if (this.publish_id) { - this.logger.info(`🎯 Currently filtering by publish_id: ${this.publish_id}`); - } - } - } catch (error) { - this.logger.error('Error detecting missing cross-references:', error); - process.exit(1); - } - } - - private async findMissingCrossReferences(): Promise { - const missingReferences: { - sourceDatasetId: number; - targetDatasetId: number; - sourcePublishId: number | null; - targetPublishId: number | null; - sourceDoi: string | null; - targetDoi: string | null; - referenceType: string; - relation: string; - doi: string | null; - reverseRelation: string; - }[] = []; - - this.logger.info('πŸ“Š Querying dataset references...'); - - // Find all references that point to Tethys datasets (DOI or URL containing tethys DOI) - // Only from datasets that are published AND only for allowed relations - const tethysReferencesQuery = DatasetReference.query() - .whereIn('type', ['DOI', 'URL']) - .whereIn('relation', this.ALLOWED_RELATIONS) // Only process allowed relations - .where((query) => { - query.where('value', 'like', '%doi.org/10.24341/tethys.%').orWhere('value', 'like', '%tethys.at/dataset/%'); - }) - .preload('dataset', (datasetQuery) => { - datasetQuery.preload('identifier'); - }) - .whereHas('dataset', (datasetQuery) => { - datasetQuery.where('server_state', 'published'); - }); - if (typeof this.publish_id === 'number') { - tethysReferencesQuery.whereHas('dataset', (datasetQuery) => { - datasetQuery.where('publish_id', this.publish_id as number); - }); - } - - const tethysReferences = await tethysReferencesQuery.exec(); - - this.logger.info(`πŸ”— Found ${tethysReferences.length} Tethys references from published datasets (allowed relations only)`); - - let processedCount = 0; - let skippedCount = 0; - - for (const reference of tethysReferences) { - processedCount++; - - if (this.verbose && processedCount % 10 === 0) { - this.logger.info(`πŸ“ˆ Processed ${processedCount}/${tethysReferences.length} references...`); - } - - // Double-check that this relation is in our allowed list (safety check) - if (!this.ALLOWED_RELATIONS.includes(reference.relation)) { - skippedCount++; - if (this.verbose) { - this.logger.info(`⏭️ Skipping relation "${reference.relation}" - not in allowed list`); - } - continue; - } - - // Extract dataset publish_id from DOI or URL - const targetDatasetPublish = this.extractDatasetPublishIdFromReference(reference.value); - - if (!targetDatasetPublish) { - if (this.verbose) { - this.logger.warning(`⚠️ Could not extract publish ID from: ${reference.value}`); - } - continue; - } - - // Check if target dataset exists and is published - const targetDataset = await Dataset.query() - .where('publish_id', targetDatasetPublish) - .where('server_state', 'published') - .preload('identifier') - .first(); - - if (!targetDataset) { - if (this.verbose) { - this.logger.warning(`⚠️ Target dataset with publish_id ${targetDatasetPublish} not found or not published`); - } - continue; - } - - // Ensure we have a valid source dataset with proper preloading - if (!reference.dataset) { - this.logger.warning(`⚠️ Source dataset ${reference.document_id} not properly loaded, skipping...`); - continue; - } - - // Check if reverse reference exists - const reverseReferenceExists = await this.checkReverseReferenceExists( - targetDataset.id, - // reference.document_id, - reference.relation, - ); - - if (!reverseReferenceExists) { - const reverseRelation = this.getReverseRelation(reference.relation); - if (reverseRelation) { - // Only add if we have a valid reverse relation - missingReferences.push({ - sourceDatasetId: reference.document_id, - targetDatasetId: targetDataset.id, - sourcePublishId: reference.dataset.publish_id || null, - targetPublishId: targetDataset.publish_id || null, - referenceType: reference.type, - relation: reference.relation, - doi: reference.value, - reverseRelation: reverseRelation, - sourceDoi: reference.dataset.identifier ? reference.dataset.identifier.value : null, - targetDoi: targetDataset.identifier ? targetDataset.identifier.value : null, - }); - } - } - } - - this.logger.info(`βœ… Processed ${processedCount} references (${skippedCount} skipped due to relation filtering)`); - return missingReferences; - } - - private extractDatasetPublishIdFromReference(value: string): number | null { - // Extract from DOI: https://doi.org/10.24341/tethys.107 -> 107 - const doiMatch = value.match(/10\.24341\/tethys\.(\d+)/); - if (doiMatch) { - return parseInt(doiMatch[1]); - } - - // Extract from URL: https://tethys.at/dataset/107 -> 107 - const urlMatch = value.match(/tethys\.at\/dataset\/(\d+)/); - if (urlMatch) { - return parseInt(urlMatch[1]); - } - - return null; - } - - private async checkReverseReferenceExists(targetDatasetId: number, originalRelation: string): Promise { - const reverseRelation = this.getReverseRelation(originalRelation); - - if (!reverseRelation) { - return true; // If no reverse relation is defined, consider it as "exists" to skip processing - } - - // Only check for reverse references where the source dataset is also published - const reverseReference = await DatasetReference.query() - // We don't filter by source document_id here to find any incoming reference from any published dataset - // .where('document_id', sourceDatasetId) - .where('related_document_id', targetDatasetId) - .where('relation', reverseRelation) - .first(); - - return !!reverseReference; - } - - private getReverseRelation(relation: string): string | null { - const relationMap: Record = { - IsNewVersionOf: 'IsPreviousVersionOf', - IsPreviousVersionOf: 'IsNewVersionOf', - IsVariantFormOf: 'IsOriginalFormOf', - IsOriginalFormOf: 'IsVariantFormOf', - }; - - // Only return reverse relation if it exists in our map, otherwise return null - return relationMap[relation] || null; - } - - private printMissingReferencesList(missingReferences: MissingCrossReference[]) { - console.log('β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”'); - console.log('β”‚ MISSING CROSS-REFERENCES REPORT β”‚'); - console.log('β”‚ (Published Datasets Only - Filtered Relations) β”‚'); - console.log('β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜'); - console.log(); - - missingReferences.forEach((missing, index) => { - console.log( - `${index + 1}. Dataset ${missing.sourceDatasetId} (Publish ID: ${missing.sourcePublishId} Identifier: ${missing.sourceDoi}) - ${missing.relation} Dataset ${missing.targetDatasetId} (Publish ID: ${missing.targetPublishId} Identifier: ${missing.targetDoi})`, - ); - console.log(` β”œβ”€ Current relation: "${missing.relation}"`); - console.log(` β”œβ”€ Missing reverse relation: "${missing.reverseRelation}"`); - console.log(` β”œβ”€ Reference type: ${missing.referenceType}`); - console.log(` └─ DOI/URL: ${missing.doi}`); - console.log(); - }); - - console.log('β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”'); - console.log(`β”‚ SUMMARY: ${missingReferences.length} missing reverse reference(s) detected β”‚`); - console.log(`β”‚ Processed relations: ${this.ALLOWED_RELATIONS.join(', ')} β”‚`); - console.log('β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜'); - } - - private async fixMissingReferences(missingReferences: MissingCrossReference[]) { - this.logger.info('πŸ”§ Creating missing cross-references in database...'); - - let fixedCount = 0; - let errorCount = 0; - - for (const [index, missing] of missingReferences.entries()) { - try { - // Get both source and target datasets - const sourceDataset = await Dataset.query() - .where('id', missing.sourceDatasetId) - .where('server_state', 'published') - .preload('identifier') - .first(); - - const targetDataset = await Dataset.query().where('id', missing.targetDatasetId).where('server_state', 'published').first(); - - if (!sourceDataset) { - this.logger.warning(`⚠️ Source dataset ${missing.sourceDatasetId} not found or not published, skipping...`); - errorCount++; - continue; - } - - if (!targetDataset) { - this.logger.warning(`⚠️ Target dataset ${missing.targetDatasetId} not found or not published, skipping...`); - errorCount++; - continue; - } - - // Create the reverse reference using the referenced_by relationship - // Example: If Dataset 297 IsNewVersionOf Dataset 144 - // We create an incoming reference for Dataset 144 that shows Dataset 297 IsPreviousVersionOf it - const reverseReference = new DatasetReference(); - // Don't set document_id - this creates an incoming reference via related_document_id - reverseReference.related_document_id = missing.targetDatasetId; // 144 (dataset receiving the incoming reference) - reverseReference.type = 'DOI'; - reverseReference.relation = missing.reverseRelation; - - // Use the source dataset's DOI for the value (what's being referenced) - if (sourceDataset.identifier?.value) { - reverseReference.value = `https://doi.org/${sourceDataset.identifier.value}`; - } else { - // Fallback to dataset URL if no DOI - reverseReference.value = `https://tethys.at/dataset/${sourceDataset.publish_id || missing.sourceDatasetId}`; - } - - // Use the source dataset's main title for the label - reverseReference.label = sourceDataset.mainTitle || `Dataset ${missing.sourceDatasetId}`; - - // Also save 'server_date_modified' on target dataset to trigger any downstream updates (e.g. search index) - targetDataset.server_date_modified = DateTime.now(); - await targetDataset.save(); - - await reverseReference.save(); - fixedCount++; - - if (this.verbose) { - this.logger.info( - `βœ… [${index + 1}/${missingReferences.length}] Created reverse reference: Dataset ${missing.sourceDatasetId} -> ${missing.targetDatasetId} (${missing.reverseRelation})`, - ); - } else if ((index + 1) % 10 === 0) { - this.logger.info(`πŸ“ˆ Fixed ${fixedCount}/${missingReferences.length} references...`); - } - } catch (error) { - this.logger.error( - `❌ Error creating reverse reference for datasets ${missing.targetDatasetId} -> ${missing.sourceDatasetId}:`, - error, - ); - errorCount++; - } - } - - this.logger.info(`πŸ“Š Fix completed: ${fixedCount} created, ${errorCount} errors`); - } -} diff --git a/commands/list_updatable_datacite.ts b/commands/list_updatable_datacite.ts deleted file mode 100644 index aed411a..0000000 --- a/commands/list_updatable_datacite.ts +++ /dev/null @@ -1,346 +0,0 @@ -/* -|-------------------------------------------------------------------------- -| node ace make:command list-updateable-datacite -| DONE: create commands/list_updeatable_datacite.ts -|-------------------------------------------------------------------------- -*/ -import { BaseCommand, flags } from '@adonisjs/core/ace'; -import { CommandOptions } from '@adonisjs/core/types/ace'; -import Dataset from '#models/dataset'; -import { DoiClient } from '#app/Library/Doi/DoiClient'; -import env from '#start/env'; -import logger from '@adonisjs/core/services/logger'; -import { DateTime } from 'luxon'; -import pLimit from 'p-limit'; - -export default class ListUpdateableDatacite extends BaseCommand { - static commandName = 'list:updateable-datacite'; - static description = 'List all datasets that need DataCite DOI updates'; - - public static needsApplication = true; - - // private chunkSize = 100; // Set chunk size for pagination - - @flags.boolean({ alias: 'v', description: 'Verbose output showing detailed information' }) - public verbose: boolean = false; - - @flags.boolean({ alias: 'c', description: 'Show only count of updatable datasets' }) - public countOnly: boolean = false; - - @flags.boolean({ alias: 'i', description: 'Show only publish IDs (useful for scripting)' }) - public idsOnly: boolean = false; - - @flags.number({ description: 'Chunk size for processing datasets (default: 50)' }) - public chunkSize: number = 50; - - //example: node ace list:updateable-datacite - //example: node ace list:updateable-datacite --verbose - //example: node ace list:updateable-datacite --count-only - //example: node ace list:updateable-datacite --ids-only - //example: node ace list:updateable-datacite --chunk-size 50 - - public static options: CommandOptions = { - startApp: true, - stayAlive: false, - }; - - async run() { - const prefix = env.get('DATACITE_PREFIX', ''); - const base_domain = env.get('BASE_DOMAIN', ''); - - if (!prefix || !base_domain) { - logger.error('Missing DATACITE_PREFIX or BASE_DOMAIN environment variables'); - return; - } - - // Prevent conflicting flags - if ((this.verbose && this.countOnly) || (this.verbose && this.idsOnly)) { - logger.error('Flags --verbose cannot be combined with --count-only or --ids-only'); - return; - } - - const chunkSize = this.chunkSize || 50; - let page = 1; - let hasMoreDatasets = true; - let totalProcessed = 0; - const updatableDatasets: Dataset[] = []; - - if (!this.countOnly && !this.idsOnly) { - logger.info(`Processing datasets in chunks of ${chunkSize}...`); - } - - while (hasMoreDatasets) { - const datasets = await this.getDatasets(page, chunkSize); - - if (datasets.length === 0) { - hasMoreDatasets = false; - break; - } - - if (!this.countOnly && !this.idsOnly) { - logger.info(`Processing chunk ${page} (${datasets.length} datasets)...`); - } - - const chunkUpdatableDatasets = await this.processChunk(datasets); - updatableDatasets.push(...chunkUpdatableDatasets); - totalProcessed += datasets.length; - - page += 1; - if (datasets.length < chunkSize) { - hasMoreDatasets = false; - } - } - - if (!this.countOnly && !this.idsOnly) { - logger.info(`Processed ${totalProcessed} datasets total, found ${updatableDatasets.length} that need updates`); - } - - if (this.countOnly) { - console.log(updatableDatasets.length); - } else if (this.idsOnly) { - updatableDatasets.forEach((dataset) => console.log(dataset.publish_id)); - } else if (this.verbose) { - await this.showVerboseOutput(updatableDatasets); - } else { - this.showSimpleOutput(updatableDatasets); - } - } - - /** - * Processes a chunk of datasets to determine which ones need DataCite updates - * - * This method handles parallel processing of datasets within a chunk, providing - * efficient error handling and filtering of results. - * - * @param datasets - Array of Dataset objects to process - * @returns Promise - Array of datasets that need updates - */ - // private async processChunk(datasets: Dataset[]): Promise { - // // Process datasets in parallel using Promise.allSettled for better error handling - // // - // // Why Promise.allSettled vs Promise.all? - // // - Promise.all fails fast: if ANY promise rejects, the entire operation fails - // // - Promise.allSettled waits for ALL promises: some can fail, others succeed - // // - This is crucial for batch processing where we don't want one bad dataset - // // to stop processing of the entire chunk - // const results = await Promise.allSettled( - // datasets.map(async (dataset) => { - // try { - // // Check if this specific dataset needs a DataCite update - // const needsUpdate = await this.shouldUpdateDataset(dataset); - - // // Return the dataset if it needs update, null if it doesn't - // // This creates a sparse array that we'll filter later - // return needsUpdate ? dataset : null; - // } catch (error) { - // // Error handling for individual dataset checks - // // - // // Log warnings only if we're not in silent modes (count-only or ids-only) - // // This prevents log spam when running automated scripts - // if (!this.countOnly && !this.idsOnly) { - // logger.warn(`Error checking dataset ${dataset.publish_id}: ${error.message}`); - // } - - // // IMPORTANT DECISION: Return the dataset anyway if we can't determine status - // // - // // Why? It's safer to include a dataset that might not need updating - // // than to miss one that actually does need updating. This follows the - // // "fail-safe" principle - if we're unsure, err on the side of caution - // return dataset; - // } - // }), - // ); - - // // Filter and extract results from Promise.allSettled response - // // - // // Promise.allSettled returns an array of objects with this structure: - // // - { status: 'fulfilled', value: T } for successful promises - // // - { status: 'rejected', reason: Error } for failed promises - // // - // // We need to: - // // 1. Only get fulfilled results (rejected ones are already handled above) - // // 2. Filter out null values (datasets that don't need updates) - // // 3. Extract the actual Dataset objects from the wrapper - // return results - // .filter( - // (result): result is PromiseFulfilledResult => - // // Type guard: only include fulfilled results that have actual values - // // This filters out: - // // - Rejected promises (shouldn't happen due to try/catch, but safety first) - // // - Fulfilled promises that returned null (datasets that don't need updates) - // result.status === 'fulfilled' && result.value !== null, - // ) - // .map((result) => result.value!); // Extract the Dataset from the wrapper - // // The ! is safe here because we filtered out null values above - // } - - private async processChunk(datasets: Dataset[]): Promise { - // Limit concurrency to avoid API flooding (e.g., max 5 at once) - const limit = pLimit(5); - - const tasks = datasets.map((dataset) => - limit(async () => { - try { - const needsUpdate = await this.shouldUpdateDataset(dataset); - return needsUpdate ? dataset : null; - } catch (error) { - if (!this.countOnly && !this.idsOnly) { - logger.warn( - `Error checking dataset ${dataset.publish_id}: ${ - error instanceof Error ? error.message : JSON.stringify(error) - }`, - ); - } - // Fail-safe: include dataset if uncertain - return dataset; - } - }), - ); - - const results = await Promise.allSettled(tasks); - - return results - .filter((result): result is PromiseFulfilledResult => result.status === 'fulfilled' && result.value !== null) - .map((result) => result.value!); - } - - private async getDatasets(page: number, chunkSize: number): Promise { - return await Dataset.query() - .orderBy('publish_id', 'asc') - .preload('identifier') - .preload('xmlCache') - .preload('titles') - .where('server_state', 'published') - .whereHas('identifier', (identifierQuery) => { - identifierQuery.where('type', 'doi'); - }) - .forPage(page, chunkSize); // Get files for the current page - } - - private async shouldUpdateDataset(dataset: Dataset): Promise { - try { - let doiIdentifier = dataset.identifier; - if (!doiIdentifier) { - await dataset.load('identifier'); - doiIdentifier = dataset.identifier; - } - - if (!doiIdentifier || doiIdentifier.type !== 'doi') { - return false; - } - - const datasetModified = - dataset.server_date_modified instanceof DateTime - ? dataset.server_date_modified - : DateTime.fromJSDate(dataset.server_date_modified); - - if (!datasetModified) { - return true; - } - - if (datasetModified > DateTime.now()) { - return false; - } - - const doiClient = new DoiClient(); - const DOI_CHECK_TIMEOUT = 300; // ms - - const doiLastModified = await Promise.race([ - doiClient.getDoiLastModified(doiIdentifier.value), - this.createTimeoutPromise(DOI_CHECK_TIMEOUT), - ]).catch(() => null); - - if (!doiLastModified) { - // If uncertain, better include dataset for update - return true; - } - - const doiModified = DateTime.fromJSDate(doiLastModified); - if (datasetModified > doiModified) { - const diffInSeconds = Math.abs(datasetModified.diff(doiModified, 'seconds').seconds); - const toleranceSeconds = 600; - return diffInSeconds > toleranceSeconds; - } - return false; - } catch (error) { - return true; // safer: include dataset if unsure - } - } - - /** - * Create a timeout promise for API calls - */ - private createTimeoutPromise(timeoutMs: number): Promise { - return new Promise((_, reject) => { - setTimeout(() => reject(new Error(`API call timeout after ${timeoutMs}ms`)), timeoutMs); - }); - } - - private showSimpleOutput(updatableDatasets: Dataset[]): void { - if (updatableDatasets.length === 0) { - console.log('No datasets need DataCite updates.'); - return; - } - - console.log(`\nFound ${updatableDatasets.length} dataset(s) that need DataCite updates:\n`); - - updatableDatasets.forEach((dataset) => { - console.log(`publish_id ${dataset.publish_id} needs update - ${dataset.mainTitle || 'Untitled'}`); - }); - - console.log(`\nTo update these datasets, run:`); - console.log(` node ace update:datacite`); - console.log(`\nOr update specific datasets:`); - console.log(` node ace update:datacite -p `); - } - - private async showVerboseOutput(updatableDatasets: Dataset[]): Promise { - if (updatableDatasets.length === 0) { - console.log('No datasets need DataCite updates.'); - return; - } - - console.log(`\nFound ${updatableDatasets.length} dataset(s) that need DataCite updates:\n`); - - for (const dataset of updatableDatasets) { - await this.showDatasetDetails(dataset); - } - - console.log(`\nSummary: ${updatableDatasets.length} datasets need updates`); - } - - private async showDatasetDetails(dataset: Dataset): Promise { - try { - let doiIdentifier = dataset.identifier; - - if (!doiIdentifier) { - await dataset.load('identifier'); - doiIdentifier = dataset.identifier; - } - - const doiValue = doiIdentifier?.value || 'N/A'; - const datasetModified = dataset.server_date_modified; - - // Get DOI info from DataCite - const doiClient = new DoiClient(); - const doiLastModified = await doiClient.getDoiLastModified(doiValue); - const doiState = await doiClient.getDoiState(doiValue); - - console.log(`β”Œβ”€ Dataset ${dataset.publish_id} ───────────────────────────────────────────────────────────────`); - console.log(`β”‚ Title: ${dataset.mainTitle || 'Untitled'}`); - console.log(`β”‚ DOI: ${doiValue}`); - console.log(`β”‚ DOI State: ${doiState || 'Unknown'}`); - console.log(`β”‚ Dataset Modified: ${datasetModified ? datasetModified.toISO() : 'N/A'}`); - console.log(`β”‚ DOI Modified: ${doiLastModified ? DateTime.fromJSDate(doiLastModified).toISO() : 'N/A'}`); - console.log(`β”‚ Status: NEEDS UPDATE`); - console.log(`└─────────────────────────────────────────────────────────────────────────────────────────────\n`); - } catch (error) { - console.log(`β”Œβ”€ Dataset ${dataset.publish_id} ───────────────────────────────────────────────────────────────`); - console.log(`β”‚ Title: ${dataset.mainTitle || 'Untitled'}`); - console.log(`β”‚ DOI: ${dataset.identifier?.value || 'N/A'}`); - console.log(`β”‚ Error: ${error.message}`); - console.log(`β”‚ Status: NEEDS UPDATE (Error checking)`); - console.log(`└─────────────────────────────────────────────────────────────────────────────────────────────\n`); - } - } -} diff --git a/commands/update_datacite.ts b/commands/update_datacite.ts deleted file mode 100644 index 7ccb0f0..0000000 --- a/commands/update_datacite.ts +++ /dev/null @@ -1,266 +0,0 @@ -/* -|-------------------------------------------------------------------------- -| node ace make:command update-datacite -| DONE: create commands/update_datacite.ts -|-------------------------------------------------------------------------- -*/ -import { BaseCommand, flags } from '@adonisjs/core/ace'; -import { CommandOptions } from '@adonisjs/core/types/ace'; -import Dataset from '#models/dataset'; -import { DoiClient } from '#app/Library/Doi/DoiClient'; -import DoiClientException from '#app/exceptions/DoiClientException'; -import Index from '#app/Library/Utils/Index'; -import env from '#start/env'; -import logger from '@adonisjs/core/services/logger'; -import { DateTime } from 'luxon'; -import { getDomain } from '#app/utils/utility-functions'; - -export default class UpdateDatacite extends BaseCommand { - static commandName = 'update:datacite'; - static description = 'Update DataCite DOI records for published datasets'; - - public static needsApplication = true; - - @flags.number({ alias: 'p', description: 'Specific publish_id to update' }) - public publish_id: number; - - @flags.boolean({ alias: 'f', description: 'Force update all records regardless of modification date' }) - public force: boolean = false; - - @flags.boolean({ alias: 'd', description: 'Dry run - show what would be updated without making changes' }) - public dryRun: boolean = false; - - @flags.boolean({ alias: 's', description: 'Show detailed stats for each dataset that needs updating' }) - public stats: boolean = false; - - //example: node ace update:datacite -p 123 --force --dry-run - - public static options: CommandOptions = { - startApp: true, // Whether to boot the application before running the command - stayAlive: false, // Whether to keep the process alive after the command has executed - }; - - async run() { - logger.info('Starting DataCite update process...'); - - const prefix = env.get('DATACITE_PREFIX', ''); - const base_domain = env.get('BASE_DOMAIN', ''); - const apiUrl = env.get('DATACITE_API_URL', 'https://api.datacite.org'); - - if (!prefix || !base_domain) { - logger.error('Missing DATACITE_PREFIX or BASE_DOMAIN environment variables'); - return; - } - - logger.info(`Using DataCite API: ${apiUrl}`); - - const datasets = await this.getDatasets(); - logger.info(`Found ${datasets.length} datasets to process`); - - let updated = 0; - let skipped = 0; - let errors = 0; - - for (const dataset of datasets) { - try { - const shouldUpdate = this.force || (await this.shouldUpdateDataset(dataset)); - - if (this.stats) { - // Stats mode: show detailed information for datasets that need updating - if (shouldUpdate) { - await this.showDatasetStats(dataset); - updated++; - } else { - skipped++; - } - continue; - } - - if (!shouldUpdate) { - logger.info(`Dataset ${dataset.publish_id}: Up to date, skipping`); - skipped++; - continue; - } - - if (this.dryRun) { - logger.info(`Dataset ${dataset.publish_id}: Would update DataCite record (dry run)`); - updated++; - continue; - } - - await this.updateDataciteRecord(dataset, prefix, base_domain); - logger.info(`Dataset ${dataset.publish_id}: Successfully updated DataCite record`); - updated++; - } catch (error) { - logger.error(`Dataset ${dataset.publish_id}: Failed to update - ${error.message}`); - errors++; - } - } - - if (this.stats) { - logger.info(`\nDataCite Stats Summary: ${updated} datasets need updating, ${skipped} are up to date`); - } else { - logger.info(`DataCite update completed. Updated: ${updated}, Skipped: ${skipped}, Errors: ${errors}`); - } - } - - private async getDatasets(): Promise { - const query = Dataset.query() - .preload('identifier') - .preload('xmlCache') - .where('server_state', 'published') - .whereHas('identifier', (identifierQuery) => { - identifierQuery.where('type', 'doi'); - }); - - if (this.publish_id) { - query.where('publish_id', this.publish_id); - } - - return await query.exec(); - } - - private async shouldUpdateDataset(dataset: Dataset): Promise { - try { - let doiIdentifier = dataset.identifier; - - if (!doiIdentifier) { - await dataset.load('identifier'); - doiIdentifier = dataset.identifier; - } - - if (!doiIdentifier || doiIdentifier.type !== 'doi') { - return false; - } - - const datasetModified = dataset.server_date_modified; - const now = DateTime.now(); - - if (!datasetModified) { - return true; // Update if modification date is missing - } - - if (datasetModified > now) { - return false; // Skip invalid future dates - } - - // Check DataCite DOI modification date - const doiClient = new DoiClient(); - const doiLastModified = await doiClient.getDoiLastModified(doiIdentifier.value); - - if (!doiLastModified) { - return false; // not Update if we can't get DOI info - } - - const doiModified = DateTime.fromJSDate(doiLastModified); - if (datasetModified > doiModified) { - // if dataset was modified after DOI creation - // Calculate the difference in seconds - const diffInSeconds = Math.abs(datasetModified.diff(doiModified, 'seconds').seconds); - - // Define tolerance threshold (60 seconds = 1 minute) - const toleranceSeconds = 60; - - // Only update if the difference is greater than the tolerance - // This prevents unnecessary updates for minor timestamp differences - return diffInSeconds > toleranceSeconds; - } else { - return false; // No update needed - } - } catch (error) { - return false; // not update if we can't determine status or other error - } - } - - private async updateDataciteRecord(dataset: Dataset, prefix: string, base_domain: string): Promise { - try { - // Get the DOI identifier (HasOne relationship) - let doiIdentifier = dataset.identifier; - - if (!doiIdentifier) { - await dataset.load('identifier'); - doiIdentifier = dataset.identifier; - } - - if (!doiIdentifier || doiIdentifier.type !== 'doi') { - throw new Error('No DOI identifier found for dataset'); - } - - // Generate XML metadata - const xmlMeta = (await Index.getDoiRegisterString(dataset)) as string; - if (!xmlMeta) { - throw new Error('Failed to generate XML metadata'); - } - - // Construct DOI value and landing page URL - const doiValue = doiIdentifier.value; // Use existing DOI value - const landingPageUrl = `https://doi.${getDomain(base_domain)}/${doiValue}`; - - // Update DataCite record - const doiClient = new DoiClient(); - const dataciteResponse = await doiClient.registerDoi(doiValue, xmlMeta, landingPageUrl); - - if (dataciteResponse?.status === 201) { - // // Update dataset modification date - // dataset.server_date_modified = DateTime.now(); - // await dataset.save(); - - // // Update search index - // const index_name = 'tethys-records'; - // await Index.indexDocument(dataset, index_name); - - logger.debug(`Dataset ${dataset.publish_id}: DataCite record and search index updated successfully`); - } else { - throw new DoiClientException( - dataciteResponse?.status || 500, - `Unexpected DataCite response code: ${dataciteResponse?.status}`, - ); - } - } catch (error) { - if (error instanceof DoiClientException) { - throw error; - } - throw new Error(`Failed to update DataCite record: ${error.message}`); - } - } - - /** - * Shows detailed statistics for a dataset that needs updating - */ - private async showDatasetStats(dataset: Dataset): Promise { - try { - let doiIdentifier = dataset.identifier; - - if (!doiIdentifier) { - await dataset.load('identifier'); - doiIdentifier = dataset.identifier; - } - - const doiValue = doiIdentifier?.value || 'N/A'; - const doiStatus = doiIdentifier?.status || 'N/A'; - const datasetModified = dataset.server_date_modified; - - // Get DOI info from DataCite - const doiClient = new DoiClient(); - const doiLastModified = await doiClient.getDoiLastModified(doiValue); - const doiState = await doiClient.getDoiState(doiValue); - - console.log(` - β”Œβ”€ Dataset ${dataset.publish_id} ─────────────────────────────────────────────────────────────── - β”‚ DOI Value: ${doiValue} - β”‚ DOI Status (DB): ${doiStatus} - β”‚ DOI State (DataCite): ${doiState || 'Unknown'} - β”‚ Dataset Modified: ${datasetModified ? datasetModified.toISO() : 'N/A'} - β”‚ DOI Modified: ${doiLastModified ? DateTime.fromJSDate(doiLastModified).toISO() : 'N/A'} - β”‚ Needs Update: YES - Dataset newer than DOI - └─────────────────────────────────────────────────────────────────────────────────────────────`); - } catch (error) { - console.log(` - β”Œβ”€ Dataset ${dataset.publish_id} ─────────────────────────────────────────────────────────────── - β”‚ DOI Value: ${dataset.identifier?.value || 'N/A'} - β”‚ Error: ${error.message} - β”‚ Needs Update: YES - Error checking status - └─────────────────────────────────────────────────────────────────────────────────────────────`); - } - } -} diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index f932a8d..8ef61c7 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -1,61 +1,47 @@ #!/bin/bash -set -e -echo "Starting ClamAV services..." +# # Run freshclam to update virus definitions +# freshclam +# # Sleep for a few seconds to give ClamAV time to start +# sleep 5 -# Try to download database if missing -if [ ! "$(ls -A /var/lib/clamav 2>/dev/null)" ]; then - echo "Downloading ClamAV database (this may take a while)..." - - # Simple freshclam run without complex config - if sg clamav -c "freshclam --datadir=/var/lib/clamav --quiet"; then - echo "βœ“ Database downloaded successfully" - else - echo "⚠ Database download failed - creating minimal setup" - # Create a dummy file so clamd doesn't immediately fail - sg clamav -c "touch /var/lib/clamav/.dummy" +# # Start the ClamAV daemon +# /etc/init.d/clamav-daemon start + +# bootstrap clam av service and clam av database updater +set -m + +function process_file() { + if [[ ! -z "$1" ]]; then + local SETTING_LIST=$(echo "$1" | tr ',' '\n' | grep "^[A-Za-z][A-Za-z]*=.*$") + local SETTING + + for SETTING in ${SETTING_LIST}; do + # Remove any existing copies of this setting. We do this here so that + # settings with multiple values (e.g. ExtraDatabase) can still be added + # multiple times below + local KEY=${SETTING%%=*} + sed -i $2 -e "/^${KEY} /d" + done + + for SETTING in ${SETTING_LIST}; do + # Split on first '=' + local KEY=${SETTING%%=*} + local VALUE=${SETTING#*=} + echo "${KEY} ${VALUE}" >> "$2" + done fi -fi +} -# Start freshclam daemon for automatic updates -echo "Starting freshclam daemon for automatic updates..." -sg clamav -c "freshclam -d" & +# process_file "${CLAMD_SETTINGS_CSV}" /etc/clamav/clamd.conf +# process_file "${FRESHCLAM_SETTINGS_CSV}" /etc/clamav/freshclam.conf +# start in background +freshclam -d & # /etc/init.d/clamav-freshclam start & -# Start clamd in background -# Start clamd in foreground (so dumb-init can supervise it) +clamd # /etc/init.d/clamav-daemon start & -# Start clamd daemon in background using sg -echo "Starting ClamAV daemon..." -# sg clamav -c "clamd" & -# Use sg to run clamd with proper group permissions -# sg clamav -c "clamd" & -sg clamav -c "clamd --config-file=/etc/clamav/clamd.conf" & - - -# Give services time to start -echo "Waiting for services to initialize..." -sleep 8 - -# simple check -if pgrep clamd > /dev/null; then - echo "βœ“ ClamAV daemon is running" -else - echo "⚠ ClamAV daemon status uncertain, but continuing..." -fi - -# Check if freshclam daemon is running -if pgrep freshclam > /dev/null; then - echo "βœ“ Freshclam daemon is running" -else - echo "⚠ Freshclam daemon status uncertain, but continuing..." -fi - -# # change back to CMD of dockerfile -# exec "$@" - -echo "βœ“ ClamAV setup complete" -echo "Starting main application..." -exec dumb-init -- "$@" \ No newline at end of file +# change back to CMD of dockerfile +exec "$@" \ No newline at end of file diff --git a/docs/commands/index-datasets.md b/docs/commands/index-datasets.md deleted file mode 100644 index baecfe6..0000000 --- a/docs/commands/index-datasets.md +++ /dev/null @@ -1,278 +0,0 @@ -# Dataset Indexing Command - -AdonisJS Ace command for indexing and synchronizing published datasets with OpenSearch for search functionality. - -## Overview - -The `index:datasets` command processes published datasets and creates/updates corresponding search index documents in OpenSearch. It intelligently compares modification timestamps to only re-index datasets when necessary, optimizing performance while maintaining search index accuracy. - -## Command Syntax - -```bash -node ace index:datasets [options] -``` - -## Options - -| Flag | Alias | Description | -|------|-------|-------------| -| `--publish_id ` | `-p` | Index a specific dataset by publish_id | - -## Usage Examples - -### Basic Operations - -```bash -# Index all published datasets that have been modified since last indexing -node ace index:datasets - -# Index a specific dataset by publish_id -node ace index:datasets --publish_id 231 -node ace index:datasets -p 231 -``` - -## How It Works - -### 1. **Dataset Selection** -The command processes datasets that meet these criteria: -- `server_state = 'published'` - Only published datasets -- Has preloaded `xmlCache` relationship for metadata transformation -- Optionally filtered by specific `publish_id` - -### 2. **Smart Update Detection** -For each dataset, the command: -- Checks if the dataset exists in the OpenSearch index -- Compares `server_date_modified` timestamps -- Only re-indexes if the dataset is newer than the indexed version - -### 3. **Document Processing** -The indexing process involves: -1. **XML Generation**: Creates structured XML from dataset metadata -2. **XSLT Transformation**: Converts XML to JSON using Saxon-JS processor -3. **Index Update**: Updates or creates the document in OpenSearch -4. **Logging**: Records success/failure for each operation - -## Index Structure - -### Index Configuration -- **Index Name**: `tethys-records` -- **Document ID**: Dataset `publish_id` -- **Refresh**: `true` (immediate availability) - -### Document Fields -The indexed documents contain: -- **Metadata Fields**: Title, description, authors, keywords -- **Identifiers**: DOI, publish_id, and other identifiers -- **Temporal Data**: Publication dates, coverage periods -- **Geographic Data**: Spatial coverage information -- **Technical Details**: Data formats, access information -- **Timestamps**: Creation and modification dates - -## Example Output - -### Successful Run -```bash -node ace index:datasets -``` -``` -Found 150 published datasets to process -Dataset with publish_id 231 successfully indexed -Dataset with publish_id 245 is up to date, skipping indexing -Dataset with publish_id 267 successfully indexed -An error occurred while indexing dataset with publish_id 289. Error: Invalid XML metadata -Processing completed: 148 indexed, 1 skipped, 1 error -``` - -### Specific Dataset -```bash -node ace index:datasets --publish_id 231 -``` -``` -Found 1 published dataset to process -Dataset with publish_id 231 successfully indexed -Processing completed: 1 indexed, 0 skipped, 0 errors -``` - -## Update Logic - -The command uses intelligent indexing to avoid unnecessary processing: - -| Condition | Action | Reason | -|-----------|--------|--------| -| Dataset not in index | βœ… Index | New dataset needs indexing | -| Dataset newer than indexed version | βœ… Re-index | Dataset has been updated | -| Dataset same/older than indexed version | ❌ Skip | Already up to date | -| OpenSearch document check fails | βœ… Index | Better safe than sorry | -| Invalid XML metadata | ❌ Skip + Log Error | Cannot process invalid data | - -### Timestamp Comparison -```typescript -// Example comparison logic -const existingModified = DateTime.fromMillis(Number(existingDoc.server_date_modified) * 1000); -const currentModified = dataset.server_date_modified; - -if (currentModified <= existingModified) { - // Skip - already up to date - return false; -} -// Proceed with indexing -``` - -## XML Transformation Process - -### 1. **XML Generation** -```xml - - - - - Research Dataset Title - Dataset description... - - - -``` - -### 2. **XSLT Processing** -The command uses Saxon-JS with a compiled stylesheet (`solr.sef.json`) to transform XML to JSON: -```javascript -const result = await SaxonJS.transform({ - stylesheetText: proc, - destination: 'serialized', - sourceText: xmlString, -}); -``` - -### 3. **Final JSON Document** -```json -{ - "id": "231", - "title": "Research Dataset Title", - "description": "Dataset description...", - "authors": ["Author Name"], - "server_date_modified": 1634567890, - "publish_id": 231 -} -``` - -## Configuration Requirements - -### Environment Variables -```bash -# OpenSearch Configuration -OPENSEARCH_HOST=localhost:9200 - -# For production: -# OPENSEARCH_HOST=your-opensearch-cluster:9200 -``` - -### Required Files -- **XSLT Stylesheet**: `public/assets2/solr.sef.json` - Compiled Saxon-JS stylesheet for XML transformation - -### Database Relationships -The command expects these model relationships: -```typescript -// Dataset model must have: -@hasOne(() => XmlCache, { foreignKey: 'dataset_id' }) -public xmlCache: HasOne -``` - -## Error Handling - -The command handles various error scenarios gracefully: - -### Common Errors and Solutions - -| Error | Cause | Solution | -|-------|-------|----------| -| `XSLT transformation failed` | Invalid XML or missing stylesheet | Check XML structure and stylesheet path | -| `OpenSearch connection error` | Service unavailable | Verify OpenSearch is running and accessible | -| `JSON parse error` | Malformed transformation result | Check XSLT stylesheet output format | -| `Missing xmlCache relationship` | Data integrity issue | Ensure xmlCache exists for dataset | - -### Error Logging -```bash -# Typical error log entry -An error occurred while indexing dataset with publish_id 231. -Error: XSLT transformation failed: Invalid XML structure at line 15 -``` - -## Performance Considerations - -### Batch Processing -- Processes datasets sequentially to avoid overwhelming OpenSearch -- Each dataset is committed individually for reliability -- Failed indexing of one dataset doesn't stop processing others - -### Resource Usage -- **Memory**: XML/JSON transformations require temporary memory -- **Network**: OpenSearch API calls for each dataset -- **CPU**: XSLT transformations are CPU-intensive - -### Optimization Tips -```bash -# Index only recently modified datasets (run regularly) -node ace index:datasets - -# Index specific datasets when needed -node ace index:datasets --publish_id 231 - -# Consider running during off-peak hours for large batches -``` - -## Integration with Other Systems - -### Search Functionality -The indexed documents power: -- **Dataset Search**: Full-text search across metadata -- **Faceted Browsing**: Filter by authors, keywords, dates -- **Geographic Search**: Spatial query capabilities -- **Auto-complete**: Suggest dataset titles and keywords - -### Related Commands -- [`update:datacite`](update-datacite.md) - Often run after indexing to sync DOI metadata -- **Database migrations** - May require re-indexing after schema changes - -### API Integration -The indexed data is consumed by: -- **Search API**: `/api/search` endpoints -- **Browse API**: `/api/datasets` with filtering -- **Recommendations**: Related dataset suggestions - -## Monitoring and Maintenance - -### Regular Tasks -```bash -# Daily indexing (recommended cron job) -0 2 * * * cd /path/to/project && node ace index:datasets - -# Weekly full re-index (if needed) -0 3 * * 0 cd /path/to/project && node ace index:datasets --force -``` - -### Health Checks -- Monitor OpenSearch cluster health -- Check for failed indexing operations in logs -- Verify search functionality is working -- Compare dataset counts between database and index - -### Troubleshooting -```bash -# Check specific dataset indexing -node ace index:datasets --publish_id 231 - -# Verify OpenSearch connectivity -curl -X GET "localhost:9200/_cluster/health" - -# Check index statistics -curl -X GET "localhost:9200/tethys-records/_stats" -``` - -## Best Practices - -1. **Regular Scheduling**: Run the command regularly (daily) to keep the search index current -2. **Monitor Logs**: Watch for transformation errors or OpenSearch issues -3. **Backup Strategy**: Include OpenSearch indices in backup procedures -4. **Resource Management**: Monitor OpenSearch cluster resources during bulk operations -5. **Testing**: Verify search functionality after major indexing operations -6. **Coordination**: Run indexing before DataCite updates when both are needed \ No newline at end of file diff --git a/docs/commands/update-datacite.md b/docs/commands/update-datacite.md deleted file mode 100644 index 06041f0..0000000 --- a/docs/commands/update-datacite.md +++ /dev/null @@ -1,216 +0,0 @@ -# DataCite Update Command - -AdonisJS Ace command for updating DataCite DOI records for published datasets. - -## Overview - -The `update:datacite` command synchronizes your local dataset metadata with DataCite DOI records. It intelligently compares modification dates to only update records when necessary, reducing unnecessary API calls and maintaining data consistency. - -## Command Syntax - -```bash -node ace update:datacite [options] -``` - -## Options - -| Flag | Alias | Description | -|------|-------|-------------| -| `--publish_id ` | `-p` | Update a specific dataset by publish_id | -| `--force` | `-f` | Force update all records regardless of modification date | -| `--dry-run` | `-d` | Preview what would be updated without making changes | -| `--stats` | `-s` | Show detailed statistics for datasets that need updating | - -## Usage Examples - -### Basic Operations - -```bash -# Update all datasets that have been modified since their DOI was last updated -node ace update:datacite - -# Update a specific dataset -node ace update:datacite --publish_id 231 -node ace update:datacite -p 231 - -# Force update all datasets with DOIs (ignores modification dates) -node ace update:datacite --force -``` - -### Preview and Analysis - -```bash -# Preview what would be updated (dry run) -node ace update:datacite --dry-run - -# Show detailed statistics for datasets that need updating -node ace update:datacite --stats - -# Show stats for a specific dataset -node ace update:datacite --stats --publish_id 231 -``` - -### Combined Options - -```bash -# Dry run for a specific dataset -node ace update:datacite --dry-run --publish_id 231 - -# Show stats for all datasets (including up-to-date ones) -node ace update:datacite --stats --force -``` - -## Command Modes - -### 1. **Normal Mode** (Default) -Updates DataCite records for datasets that have been modified since their DOI was last updated. - -**Example Output:** -``` -Using DataCite API: https://api.test.datacite.org -Found 50 datasets to process -Dataset 231: Successfully updated DataCite record -Dataset 245: Up to date, skipping -Dataset 267: Successfully updated DataCite record -DataCite update completed. Updated: 15, Skipped: 35, Errors: 0 -``` - -### 2. **Dry Run Mode** (`--dry-run`) -Shows what would be updated without making any changes to DataCite. - -**Use Case:** Preview updates before running the actual command. - -**Example Output:** -``` -Dataset 231: Would update DataCite record (dry run) -Dataset 267: Would update DataCite record (dry run) -Dataset 245: Up to date, skipping -DataCite update completed. Updated: 2, Skipped: 1, Errors: 0 -``` - -### 3. **Stats Mode** (`--stats`) -Shows detailed information for each dataset that needs updating, including why it needs updating. - -**Use Case:** Debug synchronization issues, monitor dataset/DOI status, generate reports. - -**Example Output:** -``` -β”Œβ”€ Dataset 231 ───────────────────────────────────────────────────────── -β”‚ DOI Value: 10.21388/tethys.231 -β”‚ DOI Status (DB): findable -β”‚ DOI State (DataCite): findable -β”‚ Dataset Modified: 2024-09-15T10:30:00.000Z -β”‚ DOI Modified: 2024-09-10T08:15:00.000Z -β”‚ Needs Update: YES - Dataset newer than DOI -└─────────────────────────────────────────────────────────────────────── - -β”Œβ”€ Dataset 267 ───────────────────────────────────────────────────────── -β”‚ DOI Value: 10.21388/tethys.267 -β”‚ DOI Status (DB): findable -β”‚ DOI State (DataCite): findable -β”‚ Dataset Modified: 2024-09-18T14:20:00.000Z -β”‚ DOI Modified: 2024-09-16T12:45:00.000Z -β”‚ Needs Update: YES - Dataset newer than DOI -└─────────────────────────────────────────────────────────────────────── - -DataCite Stats Summary: 2 datasets need updating, 48 are up to date -``` - -## Update Logic - -The command uses intelligent update detection: - -1. **Compares modification dates**: Dataset `server_date_modified` vs DOI last modification date from DataCite -2. **Validates data integrity**: Checks for missing or future dates -3. **Handles API failures gracefully**: Updates anyway if DataCite info can't be retrieved -4. **Uses dual API approach**: DataCite REST API (primary) with MDS API fallback - -### When Updates Happen - -| Condition | Action | Reason | -|-----------|--------|--------| -| Dataset modified > DOI modified | βœ… Update | Dataset has newer changes | -| Dataset modified ≀ DOI modified | ❌ Skip | DOI is up to date | -| Dataset date in future | ❌ Skip | Invalid data, needs investigation | -| Dataset date missing | βœ… Update | Can't determine staleness | -| DataCite API error | βœ… Update | Better safe than sorry | -| `--force` flag used | βœ… Update | Override all logic | - -## Environment Configuration - -Required environment variables: - -```bash -# DataCite Credentials -DATACITE_USERNAME=your_username -DATACITE_PASSWORD=your_password - -# API Endpoints (environment-specific) -DATACITE_API_URL=https://api.test.datacite.org # Test environment -DATACITE_SERVICE_URL=https://mds.test.datacite.org # Test MDS - -DATACITE_API_URL=https://api.datacite.org # Production -DATACITE_SERVICE_URL=https://mds.datacite.org # Production MDS - -# Project Configuration -DATACITE_PREFIX=10.21388 # Your DOI prefix -BASE_DOMAIN=tethys.at # Your domain -``` - -## Error Handling - -The command handles various error scenarios: - -- **Invalid modification dates**: Logs errors but continues processing other datasets -- **DataCite API failures**: Falls back to MDS API, then to safe update -- **Missing DOI identifiers**: Skips datasets without DOI identifiers -- **Network issues**: Continues with next dataset after logging error - -## Integration - -The command integrates with: - -- **Dataset Model**: Uses `server_date_modified` for change detection -- **DatasetIdentifier Model**: Reads DOI values and status -- **OpenSearch Index**: Updates search index after DataCite update -- **DoiClient**: Handles all DataCite API interactions - -## Common Workflows - -### Daily Maintenance -```bash -# Update any datasets modified today -node ace update:datacite -``` - -### Pre-Deployment Check -```bash -# Check what would be updated before deployment -node ace update:datacite --dry-run -``` - -### Debugging Sync Issues -```bash -# Investigate why specific dataset isn't syncing -node ace update:datacite --stats --publish_id 231 -``` - -### Full Resync -```bash -# Force update all DOI records (use with caution) -node ace update:datacite --force -``` - -### Monitoring Report -```bash -# Generate sync status report -node ace update:datacite --stats > datacite-sync-report.txt -``` - -## Best Practices - -1. **Regular Updates**: Run daily or after bulk dataset modifications -2. **Test First**: Use `--dry-run` or `--stats` before bulk operations -3. **Monitor Logs**: Check for data integrity warnings -4. **Environment Separation**: Use correct API URLs for test vs production -5. **Rate Limiting**: The command handles DataCite rate limits automatically \ No newline at end of file diff --git a/freshclam.conf b/freshclam.conf index 444a63f..ee82a23 100644 --- a/freshclam.conf +++ b/freshclam.conf @@ -1,47 +1,229 @@ ## -## Container-optimized freshclam configuration +## Example config file for freshclam +## Please read the freshclam.conf(5) manual before editing this file. ## -# Database directory + +# Comment or remove the line below. + +# Path to the database directory. +# WARNING: It must match clamd.conf's directive! +# Default: hardcoded (depends on installation options) DatabaseDirectory /var/lib/clamav -# Log to stdout for container logging +# Path to the log file (make sure it has proper permissions) +# Default: disabled # UpdateLogFile /dev/stdout -# Basic logging settings +# Maximum size of the log file. +# Value of 0 disables the limit. +# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes) +# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). +# in bytes just don't use modifiers. If LogFileMaxSize is enabled, +# log rotation (the LogRotate option) will always be enabled. +# Default: 1M +#LogFileMaxSize 2M + +# Log time with each message. +# Default: no LogTime yes -LogVerbose no + +# Enable verbose logging. +# Default: no +LogVerbose yes + +# Use system logger (can work together with UpdateLogFile). +# Default: no LogSyslog no -# PID file location +# Specify the type of syslog messages - please refer to 'man syslog' +# for facility names. +# Default: LOG_LOCAL6 +#LogFacility LOG_MAIL + +# Enable log rotation. Always enabled when LogFileMaxSize is enabled. +# Default: no +#LogRotate yes + +# This option allows you to save the process identifier of the daemon +# Default: disabled +#PidFile /var/run/freshclam.pid PidFile /var/run/clamav/freshclam.pid -# Database owner -DatabaseOwner clamav +# By default when started freshclam drops privileges and switches to the +# "clamav" user. This directive allows you to change the database owner. +# Default: clamav (may depend on installation options) +DatabaseOwner node -# Mirror settings for Austria +# Use DNS to verify virus database version. Freshclam uses DNS TXT records +# to verify database and software versions. With this directive you can change +# the database verification domain. +# WARNING: Do not touch it unless you're configuring freshclam to use your +# own database verification domain. +# Default: current.cvd.clamav.net +#DNSDatabaseInfo current.cvd.clamav.net + +# Uncomment the following line and replace XY with your country +# code. See http://www.iana.org/cctld/cctld-whois.htm for the full list. +# You can use db.XY.ipv6.clamav.net for IPv6 connections. DatabaseMirror db.at.clamav.net + +# database.clamav.net is a round-robin record which points to our most +# reliable mirrors. It's used as a fall back in case db.XY.clamav.net is +# not working. DO NOT TOUCH the following line unless you know what you +# are doing. DatabaseMirror database.clamav.net +# How many attempts to make before giving up. +# Default: 3 (per mirror) +#MaxAttempts 5 + # With this option you can control scripted updates. It's highly recommended # to keep it enabled. # Default: yes -# Update settings -ScriptedUpdates yes +#ScriptedUpdates yes + +# By default freshclam will keep the local databases (.cld) uncompressed to +# make their handling faster. With this option you can enable the compression; +# the change will take effect with the next database update. +# Default: no +#CompressLocalDatabase no + +# With this option you can provide custom sources (http:// or file://) for +# database files. This option can be used multiple times. +# Default: no custom URLs +#DatabaseCustomURL http://myserver.com/mysigs.ndb +#DatabaseCustomURL file:///mnt/nfs/local.hdb + +# This option allows you to easily point freshclam to private mirrors. +# If PrivateMirror is set, freshclam does not attempt to use DNS +# to determine whether its databases are out-of-date, instead it will +# use the If-Modified-Since request or directly check the headers of the +# remote database files. For each database, freshclam first attempts +# to download the CLD file. If that fails, it tries to download the +# CVD file. This option overrides DatabaseMirror, DNSDatabaseInfo +# and ScriptedUpdates. It can be used multiple times to provide +# fall-back mirrors. +# Default: disabled +#PrivateMirror mirror1.mynetwork.com +#PrivateMirror mirror2.mynetwork.com # Number of database checks per day. # Default: 12 (every two hours) -Checks 12 +#Checks 24 -# Don't fork (good for containers) +# Proxy settings +# Default: disabled +#HTTPProxyServer myproxy.com +#HTTPProxyPort 1234 +#HTTPProxyUsername myusername +#HTTPProxyPassword mypass + +# If your servers are behind a firewall/proxy which applies User-Agent +# filtering you can use this option to force the use of a different +# User-Agent header. +# Default: clamav/version_number +#HTTPUserAgent SomeUserAgentIdString + +# Use aaa.bbb.ccc.ddd as client address for downloading databases. Useful for +# multi-homed systems. +# Default: Use OS'es default outgoing IP address. +#LocalIPAddress aaa.bbb.ccc.ddd + +# Send the RELOAD command to clamd. +# Default: no +#NotifyClamd /path/to/clamd.conf + +# Run command after successful database update. +# Default: disabled +#OnUpdateExecute command + +# Run command when database update process fails. +# Default: disabled +#OnErrorExecute command + +# Run command when freshclam reports outdated version. +# In the command string %v will be replaced by the new version number. +# Default: disabled +#OnOutdatedExecute command + +# Don't fork into background. +# Default: no Foreground no -# Connection timeouts -ConnectTimeout 60 -ReceiveTimeout 60 +# Enable debug messages in libclamav. +# Default: no +#Debug yes -# Test databases before using them -TestDatabases yes +# Timeout in seconds when connecting to database server. +# Default: 30 +#ConnectTimeout 60 -# Enable bytecode signatures -Bytecode yes \ No newline at end of file +# Timeout in seconds when reading from database server. +# Default: 30 +#ReceiveTimeout 60 + +# With this option enabled, freshclam will attempt to load new +# databases into memory to make sure they are properly handled +# by libclamav before replacing the old ones. +# Default: yes +#TestDatabases yes + +# When enabled freshclam will submit statistics to the ClamAV Project about +# the latest virus detections in your environment. The ClamAV maintainers +# will then use this data to determine what types of malware are the most +# detected in the field and in what geographic area they are. +# Freshclam will connect to clamd in order to get recent statistics. +# Default: no +#SubmitDetectionStats /path/to/clamd.conf + +# Country of origin of malware/detection statistics (for statistical +# purposes only). The statistics collector at ClamAV.net will look up +# your IP address to determine the geographical origin of the malware +# reported by your installation. If this installation is mainly used to +# scan data which comes from a different location, please enable this +# option and enter a two-letter code (see http://www.iana.org/domains/root/db/) +# of the country of origin. +# Default: disabled +#DetectionStatsCountry country-code + +# This option enables support for our "Personal Statistics" service. +# When this option is enabled, the information on malware detected by +# your clamd installation is made available to you through our website. +# To get your HostID, log on http://www.stats.clamav.net and add a new +# host to your host list. Once you have the HostID, uncomment this option +# and paste the HostID here. As soon as your freshclam starts submitting +# information to our stats collecting service, you will be able to view +# the statistics of this clamd installation by logging into +# http://www.stats.clamav.net with the same credentials you used to +# generate the HostID. For more information refer to: +# http://www.clamav.net/documentation.html#cctts +# This feature requires SubmitDetectionStats to be enabled. +# Default: disabled +#DetectionStatsHostID unique-id + +# This option enables support for Google Safe Browsing. When activated for +# the first time, freshclam will download a new database file (safebrowsing.cvd) +# which will be automatically loaded by clamd and clamscan during the next +# reload, provided that the heuristic phishing detection is turned on. This +# database includes information about websites that may be phishing sites or +# possible sources of malware. When using this option, it's mandatory to run +# freshclam at least every 30 minutes. +# Freshclam uses the ClamAV's mirror infrastructure to distribute the +# database and its updates but all the contents are provided under Google's +# terms of use. See http://www.google.com/transparencyreport/safebrowsing +# and http://www.clamav.net/documentation.html#safebrowsing +# for more information. +# Default: disabled +#SafeBrowsing yes + +# This option enables downloading of bytecode.cvd, which includes additional +# detection mechanisms and improvements to the ClamAV engine. +# Default: enabled +#Bytecode yes + +# Download an additional 3rd party signature database distributed through +# the ClamAV mirrors. +# This option can be used multiple times. +#ExtraDatabase dbname1 +#ExtraDatabase dbname2 diff --git a/package-lock.json b/package-lock.json index f9efdac..d266b68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,9 +48,7 @@ "node-2fa": "^2.0.3", "node-exceptions": "^4.0.1", "notiwind": "^2.0.0", - "p-limit": "^7.1.1", "pg": "^8.9.0", - "pino-pretty": "^13.0.0", "qrcode": "^1.5.3", "redis": "^5.0.0", "reflect-metadata": "^0.2.1", @@ -94,6 +92,7 @@ "hot-hook": "^0.4.0", "numeral": "^2.0.6", "pinia": "^3.0.2", + "pino-pretty": "^13.0.0", "postcss-loader": "^8.1.1", "prettier": "^3.4.2", "supertest": "^6.3.3", @@ -110,9 +109,9 @@ } }, "node_modules/@adonisjs/ace": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@adonisjs/ace/-/ace-13.4.0.tgz", - "integrity": "sha512-7Wq6CpXmQm3m/6fKfzubAadCdiH2kKSni+K8s5KcTIFryKSqW+f06UAPOUwRJWqy80hnVlujAjveIsNJSPeJjA==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@adonisjs/ace/-/ace-13.3.0.tgz", + "integrity": "sha512-68dveDFd766p69cBvK/MtOrOP0+YKYLeHspa9KLEWcWk9suPf3pbGkHQ2pwDnvLJxBPHk4932KbbSSzzpGNZGw==", "license": "MIT", "dependencies": { "@poppinss/cliui": "^6.4.1", @@ -1019,48 +1018,48 @@ } }, "node_modules/@aws-sdk/client-ses": { - "version": "3.891.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.891.0.tgz", - "integrity": "sha512-X5cejGUQjUPnkD5d/SXsh6NAPRvc8JtuF+iEclbFe5OOhxJZG9YemT0V7wqC+taFe0279c89+1qJT19UjXZEeg==", + "version": "3.888.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.888.0.tgz", + "integrity": "sha512-d+mxbE8HxTF5TWAfpSL8yNpR62PfBCO5cXEAvxJq2ftvMlNPwRdyRqRddl2+86nQAnm5y6RChBkFIxr0np/F2g==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.890.0", - "@aws-sdk/credential-provider-node": "3.891.0", - "@aws-sdk/middleware-host-header": "3.891.0", - "@aws-sdk/middleware-logger": "3.891.0", - "@aws-sdk/middleware-recursion-detection": "3.891.0", - "@aws-sdk/middleware-user-agent": "3.891.0", - "@aws-sdk/region-config-resolver": "3.890.0", + "@aws-sdk/core": "3.888.0", + "@aws-sdk/credential-provider-node": "3.888.0", + "@aws-sdk/middleware-host-header": "3.887.0", + "@aws-sdk/middleware-logger": "3.887.0", + "@aws-sdk/middleware-recursion-detection": "3.887.0", + "@aws-sdk/middleware-user-agent": "3.888.0", + "@aws-sdk/region-config-resolver": "3.887.0", "@aws-sdk/types": "3.887.0", - "@aws-sdk/util-endpoints": "3.891.0", + "@aws-sdk/util-endpoints": "3.887.0", "@aws-sdk/util-user-agent-browser": "3.887.0", - "@aws-sdk/util-user-agent-node": "3.891.0", - "@smithy/config-resolver": "^4.2.2", + "@aws-sdk/util-user-agent-node": "3.888.0", + "@smithy/config-resolver": "^4.2.1", "@smithy/core": "^3.11.0", "@smithy/fetch-http-handler": "^5.2.1", "@smithy/hash-node": "^4.1.1", "@smithy/invalid-dependency": "^4.1.1", "@smithy/middleware-content-length": "^4.1.1", - "@smithy/middleware-endpoint": "^4.2.2", - "@smithy/middleware-retry": "^4.2.3", + "@smithy/middleware-endpoint": "^4.2.1", + "@smithy/middleware-retry": "^4.2.1", "@smithy/middleware-serde": "^4.1.1", "@smithy/middleware-stack": "^4.1.1", - "@smithy/node-config-provider": "^4.2.2", + "@smithy/node-config-provider": "^4.2.1", "@smithy/node-http-handler": "^4.2.1", "@smithy/protocol-http": "^5.2.1", - "@smithy/smithy-client": "^4.6.2", + "@smithy/smithy-client": "^4.6.1", "@smithy/types": "^4.5.0", "@smithy/url-parser": "^4.1.1", "@smithy/util-base64": "^4.1.0", "@smithy/util-body-length-browser": "^4.1.0", "@smithy/util-body-length-node": "^4.1.0", - "@smithy/util-defaults-mode-browser": "^4.1.2", - "@smithy/util-defaults-mode-node": "^4.1.2", - "@smithy/util-endpoints": "^3.1.2", + "@smithy/util-defaults-mode-browser": "^4.1.1", + "@smithy/util-defaults-mode-node": "^4.1.1", + "@smithy/util-endpoints": "^3.1.1", "@smithy/util-middleware": "^4.1.1", - "@smithy/util-retry": "^4.1.2", + "@smithy/util-retry": "^4.1.1", "@smithy/util-utf8": "^4.1.0", "@smithy/util-waiter": "^4.1.1", "tslib": "^2.6.2" @@ -1070,47 +1069,47 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.891.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.891.0.tgz", - "integrity": "sha512-QMDaD9GhJe7l0KQp3Tt7dzqFCz/H2XuyNjQgvi10nM1MfI1RagmLtmEhZveQxMPhZ/AtohLSK0Tisp/I5tR8RQ==", + "version": "3.888.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.888.0.tgz", + "integrity": "sha512-8CLy/ehGKUmekjH+VtZJ4w40PqDg3u0K7uPziq/4P8Q7LLgsy8YQoHNbuY4am7JU3HWrqLXJI9aaz1+vPGPoWA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.890.0", - "@aws-sdk/middleware-host-header": "3.891.0", - "@aws-sdk/middleware-logger": "3.891.0", - "@aws-sdk/middleware-recursion-detection": "3.891.0", - "@aws-sdk/middleware-user-agent": "3.891.0", - "@aws-sdk/region-config-resolver": "3.890.0", + "@aws-sdk/core": "3.888.0", + "@aws-sdk/middleware-host-header": "3.887.0", + "@aws-sdk/middleware-logger": "3.887.0", + "@aws-sdk/middleware-recursion-detection": "3.887.0", + "@aws-sdk/middleware-user-agent": "3.888.0", + "@aws-sdk/region-config-resolver": "3.887.0", "@aws-sdk/types": "3.887.0", - "@aws-sdk/util-endpoints": "3.891.0", + "@aws-sdk/util-endpoints": "3.887.0", "@aws-sdk/util-user-agent-browser": "3.887.0", - "@aws-sdk/util-user-agent-node": "3.891.0", - "@smithy/config-resolver": "^4.2.2", + "@aws-sdk/util-user-agent-node": "3.888.0", + "@smithy/config-resolver": "^4.2.1", "@smithy/core": "^3.11.0", "@smithy/fetch-http-handler": "^5.2.1", "@smithy/hash-node": "^4.1.1", "@smithy/invalid-dependency": "^4.1.1", "@smithy/middleware-content-length": "^4.1.1", - "@smithy/middleware-endpoint": "^4.2.2", - "@smithy/middleware-retry": "^4.2.3", + "@smithy/middleware-endpoint": "^4.2.1", + "@smithy/middleware-retry": "^4.2.1", "@smithy/middleware-serde": "^4.1.1", "@smithy/middleware-stack": "^4.1.1", - "@smithy/node-config-provider": "^4.2.2", + "@smithy/node-config-provider": "^4.2.1", "@smithy/node-http-handler": "^4.2.1", "@smithy/protocol-http": "^5.2.1", - "@smithy/smithy-client": "^4.6.2", + "@smithy/smithy-client": "^4.6.1", "@smithy/types": "^4.5.0", "@smithy/url-parser": "^4.1.1", "@smithy/util-base64": "^4.1.0", "@smithy/util-body-length-browser": "^4.1.0", "@smithy/util-body-length-node": "^4.1.0", - "@smithy/util-defaults-mode-browser": "^4.1.2", - "@smithy/util-defaults-mode-node": "^4.1.2", - "@smithy/util-endpoints": "^3.1.2", + "@smithy/util-defaults-mode-browser": "^4.1.1", + "@smithy/util-defaults-mode-node": "^4.1.1", + "@smithy/util-endpoints": "^3.1.1", "@smithy/util-middleware": "^4.1.1", - "@smithy/util-retry": "^4.1.2", + "@smithy/util-retry": "^4.1.1", "@smithy/util-utf8": "^4.1.0", "tslib": "^2.6.2" }, @@ -1119,19 +1118,19 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.890.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.890.0.tgz", - "integrity": "sha512-CT+yjhytHdyKvV3Nh/fqBjnZ8+UiQZVz4NMm4LrPATgVSOdfygXHqrWxrPTVgiBtuJWkotg06DF7+pTd5ekLBw==", + "version": "3.888.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.888.0.tgz", + "integrity": "sha512-L3S2FZywACo4lmWv37Y4TbefuPJ1fXWyWwIJ3J4wkPYFJ47mmtUPqThlVrSbdTHkEjnZgJe5cRfxk0qCLsFh1w==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.887.0", "@aws-sdk/xml-builder": "3.887.0", "@smithy/core": "^3.11.0", - "@smithy/node-config-provider": "^4.2.2", - "@smithy/property-provider": "^4.1.1", + "@smithy/node-config-provider": "^4.2.1", + "@smithy/property-provider": "^4.0.5", "@smithy/protocol-http": "^5.2.1", - "@smithy/signature-v4": "^5.2.1", - "@smithy/smithy-client": "^4.6.2", + "@smithy/signature-v4": "^5.1.3", + "@smithy/smithy-client": "^4.6.1", "@smithy/types": "^4.5.0", "@smithy/util-base64": "^4.1.0", "@smithy/util-body-length-browser": "^4.1.0", @@ -1145,14 +1144,14 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.890.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.890.0.tgz", - "integrity": "sha512-BtsUa2y0Rs8phmB2ScZ5RuPqZVmxJJXjGfeiXctmLFTxTwoayIK1DdNzOWx6SRMPVc3s2RBGN4vO7T1TwN+ajA==", + "version": "3.888.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.888.0.tgz", + "integrity": "sha512-shPi4AhUKbIk7LugJWvNpeZA8va7e5bOHAEKo89S0Ac8WDZt2OaNzbh/b9l0iSL2eEyte8UgIsYGcFxOwIF1VA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.890.0", + "@aws-sdk/core": "3.888.0", "@aws-sdk/types": "3.887.0", - "@smithy/property-provider": "^4.1.1", + "@smithy/property-provider": "^4.0.5", "@smithy/types": "^4.5.0", "tslib": "^2.6.2" }, @@ -1161,18 +1160,18 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.890.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.890.0.tgz", - "integrity": "sha512-0sru3LVwsuGYyzbD90EC/d5HnCZ9PL4O9BA2LYT6b9XceC005Oj86uzE47LXb+mDhTAt3T6ZO0+ZcVQe0DDi8w==", + "version": "3.888.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.888.0.tgz", + "integrity": "sha512-Jvuk6nul0lE7o5qlQutcqlySBHLXOyoPtiwE6zyKbGc7RVl0//h39Lab7zMeY2drMn8xAnIopL4606Fd8JI/Hw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.890.0", + "@aws-sdk/core": "3.888.0", "@aws-sdk/types": "3.887.0", "@smithy/fetch-http-handler": "^5.2.1", "@smithy/node-http-handler": "^4.2.1", - "@smithy/property-provider": "^4.1.1", + "@smithy/property-provider": "^4.0.5", "@smithy/protocol-http": "^5.2.1", - "@smithy/smithy-client": "^4.6.2", + "@smithy/smithy-client": "^4.6.1", "@smithy/types": "^4.5.0", "@smithy/util-stream": "^4.3.1", "tslib": "^2.6.2" @@ -1182,22 +1181,22 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.891.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.891.0.tgz", - "integrity": "sha512-9LOfm97oy2d2frwCQjl53XLkoEYG6/rsNM3Y6n8UtRU3bzGAEjixdIuv3b6Z/Mk/QLeikcQEJ9FMC02DuQh2Yw==", + "version": "3.888.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.888.0.tgz", + "integrity": "sha512-M82ItvS5yq+tO6ZOV1ruaVs2xOne+v8HW85GFCXnz8pecrzYdgxh6IsVqEbbWruryG/mUGkWMbkBZoEsy4MgyA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.890.0", - "@aws-sdk/credential-provider-env": "3.890.0", - "@aws-sdk/credential-provider-http": "3.890.0", - "@aws-sdk/credential-provider-process": "3.890.0", - "@aws-sdk/credential-provider-sso": "3.891.0", - "@aws-sdk/credential-provider-web-identity": "3.891.0", - "@aws-sdk/nested-clients": "3.891.0", + "@aws-sdk/core": "3.888.0", + "@aws-sdk/credential-provider-env": "3.888.0", + "@aws-sdk/credential-provider-http": "3.888.0", + "@aws-sdk/credential-provider-process": "3.888.0", + "@aws-sdk/credential-provider-sso": "3.888.0", + "@aws-sdk/credential-provider-web-identity": "3.888.0", + "@aws-sdk/nested-clients": "3.888.0", "@aws-sdk/types": "3.887.0", - "@smithy/credential-provider-imds": "^4.1.2", - "@smithy/property-provider": "^4.1.1", - "@smithy/shared-ini-file-loader": "^4.2.0", + "@smithy/credential-provider-imds": "^4.0.7", + "@smithy/property-provider": "^4.0.5", + "@smithy/shared-ini-file-loader": "^4.0.5", "@smithy/types": "^4.5.0", "tslib": "^2.6.2" }, @@ -1206,21 +1205,21 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.891.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.891.0.tgz", - "integrity": "sha512-IjGvQJhpCN512xlT1DFGaPeE1q0YEm/X62w7wHsRpBindW//M+heSulJzP4KPkoJvmJNVu1NxN26/p4uH+M8TQ==", + "version": "3.888.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.888.0.tgz", + "integrity": "sha512-KCrQh1dCDC8Y+Ap3SZa6S81kHk+p+yAaOQ5jC3dak4zhHW3RCrsGR/jYdemTOgbEGcA6ye51UbhWfrrlMmeJSA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.890.0", - "@aws-sdk/credential-provider-http": "3.890.0", - "@aws-sdk/credential-provider-ini": "3.891.0", - "@aws-sdk/credential-provider-process": "3.890.0", - "@aws-sdk/credential-provider-sso": "3.891.0", - "@aws-sdk/credential-provider-web-identity": "3.891.0", + "@aws-sdk/credential-provider-env": "3.888.0", + "@aws-sdk/credential-provider-http": "3.888.0", + "@aws-sdk/credential-provider-ini": "3.888.0", + "@aws-sdk/credential-provider-process": "3.888.0", + "@aws-sdk/credential-provider-sso": "3.888.0", + "@aws-sdk/credential-provider-web-identity": "3.888.0", "@aws-sdk/types": "3.887.0", - "@smithy/credential-provider-imds": "^4.1.2", - "@smithy/property-provider": "^4.1.1", - "@smithy/shared-ini-file-loader": "^4.2.0", + "@smithy/credential-provider-imds": "^4.0.7", + "@smithy/property-provider": "^4.0.5", + "@smithy/shared-ini-file-loader": "^4.0.5", "@smithy/types": "^4.5.0", "tslib": "^2.6.2" }, @@ -1229,15 +1228,15 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.890.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.890.0.tgz", - "integrity": "sha512-dWZ54TI1Q+UerF5YOqGiCzY+x2YfHsSQvkyM3T4QDNTJpb/zjiVv327VbSOULOlI7gHKWY/G3tMz0D9nWI7YbA==", + "version": "3.888.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.888.0.tgz", + "integrity": "sha512-+aX6piSukPQ8DUS4JAH344GePg8/+Q1t0+kvSHAZHhYvtQ/1Zek3ySOJWH2TuzTPCafY4nmWLcQcqvU1w9+4Lw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.890.0", + "@aws-sdk/core": "3.888.0", "@aws-sdk/types": "3.887.0", - "@smithy/property-provider": "^4.1.1", - "@smithy/shared-ini-file-loader": "^4.2.0", + "@smithy/property-provider": "^4.0.5", + "@smithy/shared-ini-file-loader": "^4.0.5", "@smithy/types": "^4.5.0", "tslib": "^2.6.2" }, @@ -1246,17 +1245,17 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.891.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.891.0.tgz", - "integrity": "sha512-RtF9BwUIZqc/7sFbK6n6qhe0tNaWJQwin89nSeZ1HOsA0Z7TfTOelX8Otd0L5wfeVBMVcgiN3ofqrcZgjFjQjA==", + "version": "3.888.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.888.0.tgz", + "integrity": "sha512-b1ZJji7LJ6E/j1PhFTyvp51in2iCOQ3VP6mj5H6f5OUnqn7efm41iNMoinKr87n0IKZw7qput5ggXVxEdPhouA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-sso": "3.891.0", - "@aws-sdk/core": "3.890.0", - "@aws-sdk/token-providers": "3.891.0", + "@aws-sdk/client-sso": "3.888.0", + "@aws-sdk/core": "3.888.0", + "@aws-sdk/token-providers": "3.888.0", "@aws-sdk/types": "3.887.0", - "@smithy/property-provider": "^4.1.1", - "@smithy/shared-ini-file-loader": "^4.2.0", + "@smithy/property-provider": "^4.0.5", + "@smithy/shared-ini-file-loader": "^4.0.5", "@smithy/types": "^4.5.0", "tslib": "^2.6.2" }, @@ -1265,16 +1264,15 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.891.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.891.0.tgz", - "integrity": "sha512-yq7kzm1sHZ0GZrtS+qpjMUp4ES66UoT1+H2xxrOuAZkvUnkpQq1iSjOgBgJJ9FW1EsDUEmlgn94i4hJTNvm7fg==", + "version": "3.888.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.888.0.tgz", + "integrity": "sha512-7P0QNtsDzMZdmBAaY/vY1BsZHwTGvEz3bsn2bm5VSKFAeMmZqsHK1QeYdNsFjLtegnVh+wodxMq50jqLv3LFlA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.890.0", - "@aws-sdk/nested-clients": "3.891.0", + "@aws-sdk/core": "3.888.0", + "@aws-sdk/nested-clients": "3.888.0", "@aws-sdk/types": "3.887.0", - "@smithy/property-provider": "^4.1.1", - "@smithy/shared-ini-file-loader": "^4.2.0", + "@smithy/property-provider": "^4.0.5", "@smithy/types": "^4.5.0", "tslib": "^2.6.2" }, @@ -1283,9 +1281,9 @@ } }, "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.891.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.891.0.tgz", - "integrity": "sha512-OYaxbqNDeo/noE7MfYWWQDu86cF/R/bMXdZ2QZwpWpX2yjy8xMwxSg7c/4tEK/OtiDZTKRXXrvPxRxG2+1bnJw==", + "version": "3.887.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.887.0.tgz", + "integrity": "sha512-ulzqXv6NNqdu/kr0sgBYupWmahISHY+azpJidtK6ZwQIC+vBUk9NdZeqQpy7KVhIk2xd4+5Oq9rxapPwPI21CA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.887.0", @@ -1298,9 +1296,9 @@ } }, "node_modules/@aws-sdk/middleware-logger": { - "version": "3.891.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.891.0.tgz", - "integrity": "sha512-azL4mg1H1FLpOAECiFtU+r+9VDhpeF6Vh9pzD4m51BWPJ60CVnyHayeI/0gqPsL60+5l90/b9VWonoA8DvAvpg==", + "version": "3.887.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.887.0.tgz", + "integrity": "sha512-YbbgLI6jKp2qSoAcHnXrQ5jcuc5EYAmGLVFgMVdk8dfCfJLfGGSaOLxF4CXC7QYhO50s+mPPkhBYejCik02Kug==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.887.0", @@ -1312,9 +1310,9 @@ } }, "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.891.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.891.0.tgz", - "integrity": "sha512-n++KwAEnNlvx5NZdIQZnvl2GjSH/YE3xGSqW2GmPB5780tFY5lOYSb1uA+EUzJSVX4oAKAkSPdR2AOW09kzoew==", + "version": "3.887.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.887.0.tgz", + "integrity": "sha512-tjrUXFtQnFLo+qwMveq5faxP5MQakoLArXtqieHphSqZTXm21wDJM73hgT4/PQQGTwgYjDKqnqsE1hvk0hcfDw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.887.0", @@ -1328,14 +1326,14 @@ } }, "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.891.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.891.0.tgz", - "integrity": "sha512-xyxIZtR7FunCWymPAxEm61VUq9lruXxWIYU5AIh5rt0av7nXa2ayAAlscQ7ch9jUlw+lbC2PVbw0K/OYrMovuA==", + "version": "3.888.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.888.0.tgz", + "integrity": "sha512-ZkcUkoys8AdrNNG7ATjqw2WiXqrhTvT+r4CIK3KhOqIGPHX0p0DQWzqjaIl7ZhSUToKoZ4Ud7MjF795yUr73oA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.890.0", + "@aws-sdk/core": "3.888.0", "@aws-sdk/types": "3.887.0", - "@aws-sdk/util-endpoints": "3.891.0", + "@aws-sdk/util-endpoints": "3.887.0", "@smithy/core": "^3.11.0", "@smithy/protocol-http": "^5.2.1", "@smithy/types": "^4.5.0", @@ -1346,47 +1344,47 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.891.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.891.0.tgz", - "integrity": "sha512-cpol+Yk4T3GXPXbRfUyN2u6tpMEHUxAiesZgrfMm11QGHV+pmzyejJV/QZ0pdJKj5sXKaCr4DCntoJ5iBx++Cw==", + "version": "3.888.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.888.0.tgz", + "integrity": "sha512-py4o4RPSGt+uwGvSBzR6S6cCBjS4oTX5F8hrHFHfPCdIOMVjyOBejn820jXkCrcdpSj3Qg1yUZXxsByvxc9Lyg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.890.0", - "@aws-sdk/middleware-host-header": "3.891.0", - "@aws-sdk/middleware-logger": "3.891.0", - "@aws-sdk/middleware-recursion-detection": "3.891.0", - "@aws-sdk/middleware-user-agent": "3.891.0", - "@aws-sdk/region-config-resolver": "3.890.0", + "@aws-sdk/core": "3.888.0", + "@aws-sdk/middleware-host-header": "3.887.0", + "@aws-sdk/middleware-logger": "3.887.0", + "@aws-sdk/middleware-recursion-detection": "3.887.0", + "@aws-sdk/middleware-user-agent": "3.888.0", + "@aws-sdk/region-config-resolver": "3.887.0", "@aws-sdk/types": "3.887.0", - "@aws-sdk/util-endpoints": "3.891.0", + "@aws-sdk/util-endpoints": "3.887.0", "@aws-sdk/util-user-agent-browser": "3.887.0", - "@aws-sdk/util-user-agent-node": "3.891.0", - "@smithy/config-resolver": "^4.2.2", + "@aws-sdk/util-user-agent-node": "3.888.0", + "@smithy/config-resolver": "^4.2.1", "@smithy/core": "^3.11.0", "@smithy/fetch-http-handler": "^5.2.1", "@smithy/hash-node": "^4.1.1", "@smithy/invalid-dependency": "^4.1.1", "@smithy/middleware-content-length": "^4.1.1", - "@smithy/middleware-endpoint": "^4.2.2", - "@smithy/middleware-retry": "^4.2.3", + "@smithy/middleware-endpoint": "^4.2.1", + "@smithy/middleware-retry": "^4.2.1", "@smithy/middleware-serde": "^4.1.1", "@smithy/middleware-stack": "^4.1.1", - "@smithy/node-config-provider": "^4.2.2", + "@smithy/node-config-provider": "^4.2.1", "@smithy/node-http-handler": "^4.2.1", "@smithy/protocol-http": "^5.2.1", - "@smithy/smithy-client": "^4.6.2", + "@smithy/smithy-client": "^4.6.1", "@smithy/types": "^4.5.0", "@smithy/url-parser": "^4.1.1", "@smithy/util-base64": "^4.1.0", "@smithy/util-body-length-browser": "^4.1.0", "@smithy/util-body-length-node": "^4.1.0", - "@smithy/util-defaults-mode-browser": "^4.1.2", - "@smithy/util-defaults-mode-node": "^4.1.2", - "@smithy/util-endpoints": "^3.1.2", + "@smithy/util-defaults-mode-browser": "^4.1.1", + "@smithy/util-defaults-mode-node": "^4.1.1", + "@smithy/util-endpoints": "^3.1.1", "@smithy/util-middleware": "^4.1.1", - "@smithy/util-retry": "^4.1.2", + "@smithy/util-retry": "^4.1.1", "@smithy/util-utf8": "^4.1.0", "tslib": "^2.6.2" }, @@ -1395,15 +1393,15 @@ } }, "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.890.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.890.0.tgz", - "integrity": "sha512-VfdT+tkF9groRYNzKvQCsCGDbOQdeBdzyB1d6hWiq22u13UafMIoskJ1ec0i0H1X29oT6mjTitfnvPq1UiKwzQ==", + "version": "3.887.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.887.0.tgz", + "integrity": "sha512-VdSMrIqJ3yjJb/fY+YAxrH/lCVv0iL8uA+lbMNfQGtO5tB3Zx6SU9LEpUwBNX8fPK1tUpI65CNE4w42+MY/7Mg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.887.0", - "@smithy/node-config-provider": "^4.2.2", + "@smithy/node-config-provider": "^4.2.1", "@smithy/types": "^4.5.0", - "@smithy/util-config-provider": "^4.1.0", + "@smithy/util-config-provider": "^4.0.0", "@smithy/util-middleware": "^4.1.1", "tslib": "^2.6.2" }, @@ -1412,16 +1410,16 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.891.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.891.0.tgz", - "integrity": "sha512-n31JDMWhj/53QX33C97+1W63JGtgO8pg1/Tfmv4f9TR2VSGf1rFwYH7cPZ7dVIMmcUBeI2VCVhwUIabGNHw86Q==", + "version": "3.888.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.888.0.tgz", + "integrity": "sha512-WA3NF+3W8GEuCMG1WvkDYbB4z10G3O8xuhT7QSjhvLYWQ9CPt3w4VpVIfdqmUn131TCIbhCzD0KN/1VJTjAjyw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.890.0", - "@aws-sdk/nested-clients": "3.891.0", + "@aws-sdk/core": "3.888.0", + "@aws-sdk/nested-clients": "3.888.0", "@aws-sdk/types": "3.887.0", - "@smithy/property-provider": "^4.1.1", - "@smithy/shared-ini-file-loader": "^4.2.0", + "@smithy/property-provider": "^4.0.5", + "@smithy/shared-ini-file-loader": "^4.0.5", "@smithy/types": "^4.5.0", "tslib": "^2.6.2" }, @@ -1443,15 +1441,15 @@ } }, "node_modules/@aws-sdk/util-endpoints": { - "version": "3.891.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.891.0.tgz", - "integrity": "sha512-MgxvmHIQJbUK+YquX4bdjDw1MjdBqTRJGHs6iU2KM8nN1ut0bPwvavkq7NrY/wB3ZKKECqmv6J/nw+hYKKUIHA==", + "version": "3.887.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.887.0.tgz", + "integrity": "sha512-kpegvT53KT33BMeIcGLPA65CQVxLUL/C3gTz9AzlU/SDmeusBHX4nRApAicNzI/ltQ5lxZXbQn18UczzBuwF1w==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.887.0", "@smithy/types": "^4.5.0", "@smithy/url-parser": "^4.1.1", - "@smithy/util-endpoints": "^3.1.2", + "@smithy/util-endpoints": "^3.1.1", "tslib": "^2.6.2" }, "engines": { @@ -1483,14 +1481,14 @@ } }, "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.891.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.891.0.tgz", - "integrity": "sha512-/mmvVL2PJE2NMTWj9JSY98OISx7yov0mi72eOViWCHQMRYJCN12DY54i1rc4Q/oPwJwTwIrx69MLjVhQ1OZsgw==", + "version": "3.888.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.888.0.tgz", + "integrity": "sha512-rSB3OHyuKXotIGfYEo//9sU0lXAUrTY28SUUnxzOGYuQsAt0XR5iYwBAp+RjV6x8f+Hmtbg0PdCsy1iNAXa0UQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-user-agent": "3.891.0", + "@aws-sdk/middleware-user-agent": "3.888.0", "@aws-sdk/types": "3.887.0", - "@smithy/node-config-provider": "^4.2.2", + "@smithy/node-config-provider": "^4.2.1", "@smithy/types": "^4.5.0", "tslib": "^2.6.2" }, @@ -2018,9 +2016,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", - "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", "cpu": [ "ppc64" ], @@ -2034,9 +2032,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", - "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", "cpu": [ "arm" ], @@ -2050,9 +2048,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", - "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", "cpu": [ "arm64" ], @@ -2066,9 +2064,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", - "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", "cpu": [ "x64" ], @@ -2082,9 +2080,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", - "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", "cpu": [ "arm64" ], @@ -2098,9 +2096,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", - "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", "cpu": [ "x64" ], @@ -2114,9 +2112,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", - "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", "cpu": [ "arm64" ], @@ -2130,9 +2128,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", - "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", "cpu": [ "x64" ], @@ -2146,9 +2144,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", - "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", "cpu": [ "arm" ], @@ -2162,9 +2160,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", - "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", "cpu": [ "arm64" ], @@ -2178,9 +2176,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", - "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", "cpu": [ "ia32" ], @@ -2194,9 +2192,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", - "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", "cpu": [ "loong64" ], @@ -2210,9 +2208,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", - "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", "cpu": [ "mips64el" ], @@ -2226,9 +2224,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", - "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", "cpu": [ "ppc64" ], @@ -2242,9 +2240,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", - "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", "cpu": [ "riscv64" ], @@ -2258,9 +2256,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", - "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", "cpu": [ "s390x" ], @@ -2274,9 +2272,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", - "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", "cpu": [ "x64" ], @@ -2290,9 +2288,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", - "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", "cpu": [ "arm64" ], @@ -2306,9 +2304,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", - "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", "cpu": [ "x64" ], @@ -2322,9 +2320,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", - "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", "cpu": [ "arm64" ], @@ -2338,9 +2336,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", - "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", "cpu": [ "x64" ], @@ -2354,9 +2352,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", - "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", "cpu": [ "arm64" ], @@ -2370,9 +2368,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", - "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", "cpu": [ "x64" ], @@ -2386,9 +2384,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", - "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", "cpu": [ "arm64" ], @@ -2402,9 +2400,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", - "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", "cpu": [ "ia32" ], @@ -2418,9 +2416,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", - "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", "cpu": [ "x64" ], @@ -2513,18 +2511,18 @@ } }, "node_modules/@fontsource/archivo-black": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/@fontsource/archivo-black/-/archivo-black-5.2.8.tgz", - "integrity": "sha512-3zNj/o9LzWyDl/UEpY5IOHpAQyUtFr3hQaFS7NSKwCLLkXOfH/CMCt1L2b2Z+OF25OURtOYenCadgAebALz7/A==", + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@fontsource/archivo-black/-/archivo-black-5.2.6.tgz", + "integrity": "sha512-Jxq9D0G9k9OfKvx8tQO9WZ6bfNqcN99UoQ2fJivn1JPkY/vVbK/uzHn2BPj347Vh9oNQBUpKaQ9NoDUKLJPQ/w==", "license": "OFL-1.1", "funding": { "url": "https://github.com/sponsors/ayuhito" } }, "node_modules/@fontsource/inter": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.8.tgz", - "integrity": "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==", + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.6.tgz", + "integrity": "sha512-CZs9S1CrjD0jPwsNy9W6j0BhsmRSQrgwlTNkgQXTsAeDRM42LBRLo3eo9gCzfH4GvV7zpyf78Ozfl773826csw==", "license": "OFL-1.1", "funding": { "url": "https://github.com/sponsors/ayuhito" @@ -2598,13 +2596,13 @@ } }, "node_modules/@inertiajs/core": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@inertiajs/core/-/core-2.1.7.tgz", - "integrity": "sha512-ahBSdNj4d7oqEBr5KcGPVuoyI3JWYKwwLjqhy2O4Jp/UKX1C6W0U/WkpL6NzCapNaNDACBVSc3rqZ/6lY0VbWA==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@inertiajs/core/-/core-2.1.6.tgz", + "integrity": "sha512-PvY3QJecHt/Z+X+C+jJOHnBGxvi6YNuX3tLY0oXA2yC8aQZeUHnIoWnQdKgc0KA0CNj3b3sZSxm2ZQs9nMY7/Q==", "license": "MIT", "dependencies": { "@types/lodash-es": "^4.17.12", - "axios": "^1.12.0", + "axios": "^1.11.0", "lodash-es": "^4.17.21", "qs": "^6.9.0" } @@ -2630,12 +2628,12 @@ } }, "node_modules/@inertiajs/vue3": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@inertiajs/vue3/-/vue3-2.1.7.tgz", - "integrity": "sha512-Y6sL2lBJ/uJNVRL4FnYKAp7xdoWwgpc4HvlP8RZhm6roHUBcQNZWxxrPqhtBSx5v9vcTeIvu4+TsoFetPSYgdw==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@inertiajs/vue3/-/vue3-2.1.6.tgz", + "integrity": "sha512-r2tCjCe8kSPaEsbZFphKWnKZQ2/2ZItvrB3HWYCwl0ZS0wY396IsZcCpeJKFhF1xCoAnNYpfZo10dvcRmCipfQ==", "license": "MIT", "dependencies": { - "@inertiajs/core": "2.1.7", + "@inertiajs/core": "2.1.6", "@types/lodash-es": "^4.17.12", "lodash-es": "^4.17.21" }, @@ -2644,9 +2642,9 @@ } }, "node_modules/@ioredis/commands": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.4.0.tgz", - "integrity": "sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.3.1.tgz", + "integrity": "sha512-bYtU8avhGIcje3IhvF9aSjsa5URMZBHnwKtOvXsT4sfYy9gppW11gLPT/9oNqlJZD47yPKveQFTAFWpHjKvUoQ==", "license": "MIT" }, "node_modules/@isaacs/cliui": { @@ -3020,9 +3018,9 @@ } }, "node_modules/@jsonjoy.com/json-pack": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.14.0.tgz", - "integrity": "sha512-LpWbYgVnKzphN5S6uss4M25jJ/9+m6q6UJoeN6zTkK4xAGhKsiBRPVeF7OYMWonn5repMQbE5vieRXcMUrKDKw==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.11.0.tgz", + "integrity": "sha512-nLqSTAYwpk+5ZQIoVp7pfd/oSKNWlEdvTq2LzVA4r2wtWZg6v+5u0VgBOaDJuUfNOuw/4Ysq6glN5QKSrOCgrA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3567,9 +3565,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.51.0.tgz", - "integrity": "sha512-VyfldO8T/C5vAXBGIobrAnUE+VJNVLw5z9h4NgSDq/AJZWt/fXqdW+0PJbk+M74xz7yMDRiHtlsuDV7ew6K20w==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.1.tgz", + "integrity": "sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==", "cpu": [ "arm" ], @@ -3580,9 +3578,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.51.0.tgz", - "integrity": "sha512-Z3ujzDZgsEVSokgIhmOAReh9SGT2qloJJX2Xo1Q3nPU1EhCXrV0PbpR3r7DWRgozqnjrPZQkLe5cgBPIYp70Vg==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.1.tgz", + "integrity": "sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==", "cpu": [ "arm64" ], @@ -3593,9 +3591,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.51.0.tgz", - "integrity": "sha512-T3gskHgArUdR6TCN69li5VELVAZK+iQ4iwMoSMNYixoj+56EC9lTj35rcxhXzIJt40YfBkvDy3GS+t5zh7zM6g==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.1.tgz", + "integrity": "sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==", "cpu": [ "arm64" ], @@ -3606,9 +3604,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.51.0.tgz", - "integrity": "sha512-Hh7n/fh0g5UjH6ATDF56Qdf5bzdLZKIbhp5KftjMYG546Ocjeyg15dxphCpH1FFY2PJ2G6MiOVL4jMq5VLTyrQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.1.tgz", + "integrity": "sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==", "cpu": [ "x64" ], @@ -3619,9 +3617,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.51.0.tgz", - "integrity": "sha512-0EddADb6FBvfqYoxwVom3hAbAvpSVUbZqmR1wmjk0MSZ06hn/UxxGHKRqEQDMkts7XiZjejVB+TLF28cDTU+gA==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.1.tgz", + "integrity": "sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==", "cpu": [ "arm64" ], @@ -3632,9 +3630,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.51.0.tgz", - "integrity": "sha512-MpqaEDLo3JuVPF+wWV4mK7V8akL76WCz8ndfz1aVB7RhvXFO3k7yT7eu8OEuog4VTSyNu5ibvN9n6lgjq/qLEQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.1.tgz", + "integrity": "sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==", "cpu": [ "x64" ], @@ -3645,9 +3643,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.51.0.tgz", - "integrity": "sha512-WEWAGFNFFpvSWAIT3MYvxTkYHv/cJl9yWKpjhheg7ONfB0hetZt/uwBnM3GZqSHrk5bXCDYTFXg3jQyk/j7eXQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.1.tgz", + "integrity": "sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==", "cpu": [ "arm" ], @@ -3658,9 +3656,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.51.0.tgz", - "integrity": "sha512-9bxtxj8QoAp++LOq5PGDGkEEOpCDk9rOEHUcXadnijedDH8IXrBt6PnBa4Y6NblvGWdoxvXZYghZLaliTCmAng==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.1.tgz", + "integrity": "sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==", "cpu": [ "arm" ], @@ -3671,9 +3669,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.51.0.tgz", - "integrity": "sha512-DdqA+fARqIsfqDYkKo2nrWMp0kvu/wPJ2G8lZ4DjYhn+8QhrjVuzmsh7tTkhULwjvHTN59nWVzAixmOi6rqjNA==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.1.tgz", + "integrity": "sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==", "cpu": [ "arm64" ], @@ -3684,9 +3682,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.51.0.tgz", - "integrity": "sha512-2XVRNzcUJE1UJua8P4a1GXS5jafFWE+pQ6zhUbZzptOu/70p1F6+0FTi6aGPd6jNtnJqGMjtBCXancC2dhYlWw==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.1.tgz", + "integrity": "sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==", "cpu": [ "arm64" ], @@ -3696,10 +3694,10 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.51.0.tgz", - "integrity": "sha512-R8QhY0kLIPCAVXWi2yftDSpn7Jtejey/WhMoBESSfwGec5SKdFVupjxFlKoQ7clVRuaDpiQf7wNx3EBZf4Ey6g==", + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.1.tgz", + "integrity": "sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==", "cpu": [ "loong64" ], @@ -3710,9 +3708,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.51.0.tgz", - "integrity": "sha512-I498RPfxx9cMv1KTHQ9tg2Ku1utuQm+T5B+Xro+WNu3FzAFSKp4awKfgMoZwjoPgNbaFGINaOM25cQW6WuBhiQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.1.tgz", + "integrity": "sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==", "cpu": [ "ppc64" ], @@ -3723,9 +3721,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.51.0.tgz", - "integrity": "sha512-o8COudsb8lvtdm9ixg9aKjfX5aeoc2x9KGE7WjtrmQFquoCRZ9jtzGlonujE4WhvXFepTraWzT4RcwyDDeHXjA==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.1.tgz", + "integrity": "sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==", "cpu": [ "riscv64" ], @@ -3736,9 +3734,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.51.0.tgz", - "integrity": "sha512-0shJPgSXMdYzOQzpM5BJN2euXY1f8uV8mS6AnrbMcH2KrkNsbpMxWB1wp8UEdiJ1NtyBkCk3U/HfX5mEONBq6w==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.1.tgz", + "integrity": "sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==", "cpu": [ "riscv64" ], @@ -3749,9 +3747,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.51.0.tgz", - "integrity": "sha512-L7pV+ny7865jamSCQwyozBYjFRUKaTsPqDz7ClOtJCDu4paf2uAa0mrcHwSt4XxZP2ogFZS9uuitH3NXdeBEJA==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.1.tgz", + "integrity": "sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==", "cpu": [ "s390x" ], @@ -3762,9 +3760,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.51.0.tgz", - "integrity": "sha512-4YHhP+Rv3T3+H3TPbUvWOw5tuSwhrVhkHHZhk4hC9VXeAOKR26/IsUAT4FsB4mT+kfIdxxb1BezQDEg/voPO8A==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.1.tgz", + "integrity": "sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==", "cpu": [ "x64" ], @@ -3775,9 +3773,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.51.0.tgz", - "integrity": "sha512-P7U7U03+E5w7WgJtvSseNLOX1UhknVPmEaqgUENFWfNxNBa1OhExT6qYGmyF8gepcxWSaSfJsAV5UwhWrYefdQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.1.tgz", + "integrity": "sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==", "cpu": [ "x64" ], @@ -3788,9 +3786,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.51.0.tgz", - "integrity": "sha512-FuD8g3u9W6RPwdO1R45hZFORwa1g9YXEMesAKP/sOi7mDqxjbni8S3zAXJiDcRfGfGBqpRYVuH54Gu3FTuSoEw==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.1.tgz", + "integrity": "sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==", "cpu": [ "arm64" ], @@ -3801,9 +3799,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.51.0.tgz", - "integrity": "sha512-zST+FdMCX3QAYfmZX3dp/Fy8qLUetfE17QN5ZmmFGPrhl86qvRr+E9u2bk7fzkIXsfQR30Z7ZRS7WMryPPn4rQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.1.tgz", + "integrity": "sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==", "cpu": [ "arm64" ], @@ -3814,9 +3812,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.51.0.tgz", - "integrity": "sha512-U+qhoCVAZmTHCmUKxdQxw1jwAFNFXmOpMME7Npt5GTb1W/7itfgAgNluVOvyeuSeqW+dEQLFuNZF3YZPO8XkMg==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.1.tgz", + "integrity": "sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==", "cpu": [ "ia32" ], @@ -3827,9 +3825,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.51.0.tgz", - "integrity": "sha512-z6UpFzMhXSD8NNUfCi2HO+pbpSzSWIIPgb1TZsEZjmZYtk6RUIC63JYjlFBwbBZS3jt3f1q6IGfkj3g+GnBt2Q==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.1.tgz", + "integrity": "sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==", "cpu": [ "x64" ], @@ -3853,9 +3851,9 @@ "license": "MIT" }, "node_modules/@sindresorhus/is": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.1.0.tgz", - "integrity": "sha512-7F/yz2IphV39hiS2zB4QYVkivrptHHh0K8qJJd9HhuWSdvf8AN7NpebW3CcDZDBQsUPMoDKWsY2WWgW7bqOcfA==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.0.2.tgz", + "integrity": "sha512-d9xRovfKNz1SKieM0qJdO+PQonjnnIfSNWfHYnBSJ9hkjm0ZPw6HlxscDXYstp3z+7V2GOFHc+J0CYrYTjqCJw==", "license": "MIT", "engines": { "node": ">=18" @@ -3891,12 +3889,12 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.2.2.tgz", - "integrity": "sha512-IT6MatgBWagLybZl1xQcURXRICvqz1z3APSCAI9IqdvfCkrA7RaQIEfgC6G/KvfxnDfQUDqFV+ZlixcuFznGBQ==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.2.1.tgz", + "integrity": "sha512-FXil8q4QN7mgKwU2hCLm0ltab8NyY/1RiqEf25Jnf6WLS3wmb11zGAoLETqg1nur2Aoibun4w4MjeN9CMJ4G6A==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.2.2", + "@smithy/node-config-provider": "^4.2.1", "@smithy/types": "^4.5.0", "@smithy/util-config-provider": "^4.1.0", "@smithy/util-middleware": "^4.1.1", @@ -3907,9 +3905,9 @@ } }, "node_modules/@smithy/core": { - "version": "3.11.1", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.11.1.tgz", - "integrity": "sha512-REH7crwORgdjSpYs15JBiIWOYjj0hJNC3aCecpJvAlMMaaqL5i2CLb1i6Hc4yevToTKSqslLMI9FKjhugEwALA==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.11.0.tgz", + "integrity": "sha512-Abs5rdP1o8/OINtE49wwNeWuynCu0kme1r4RI3VXVrHr4odVDG7h7mTnw1WXXfN5Il+c25QOnrdL2y56USfxkA==", "license": "Apache-2.0", "dependencies": { "@smithy/middleware-serde": "^4.1.1", @@ -3918,7 +3916,7 @@ "@smithy/util-base64": "^4.1.0", "@smithy/util-body-length-browser": "^4.1.0", "@smithy/util-middleware": "^4.1.1", - "@smithy/util-stream": "^4.3.2", + "@smithy/util-stream": "^4.3.1", "@smithy/util-utf8": "^4.1.0", "@types/uuid": "^9.0.1", "tslib": "^2.6.2", @@ -3929,12 +3927,12 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.1.2.tgz", - "integrity": "sha512-JlYNq8TShnqCLg0h+afqe2wLAwZpuoSgOyzhYvTgbiKBWRov+uUve+vrZEQO6lkdLOWPh7gK5dtb9dS+KGendg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.1.1.tgz", + "integrity": "sha512-1WdBfM9DwA59pnpIizxnUvBf/de18p4GP+6zP2AqrlFzoW3ERpZaT4QueBR0nS9deDMaQRkBlngpVlnkuuTisQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.2.2", + "@smithy/node-config-provider": "^4.2.1", "@smithy/property-provider": "^4.1.1", "@smithy/types": "^4.5.0", "@smithy/url-parser": "^4.1.1", @@ -4015,15 +4013,15 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.2.3.tgz", - "integrity": "sha512-+1H5A28DeffRVrqmVmtqtRraEjoaC6JVap3xEQdVoBh2EagCVY7noPmcBcG4y7mnr9AJitR1ZAse2l+tEtK5vg==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.2.1.tgz", + "integrity": "sha512-fUTMmQvQQZakXOuKizfu7fBLDpwvWZjfH6zUK2OLsoNZRZGbNUdNSdLJHpwk1vS208jtDjpUIskh+JoA8zMzZg==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.11.1", + "@smithy/core": "^3.11.0", "@smithy/middleware-serde": "^4.1.1", - "@smithy/node-config-provider": "^4.2.2", - "@smithy/shared-ini-file-loader": "^4.2.0", + "@smithy/node-config-provider": "^4.2.1", + "@smithy/shared-ini-file-loader": "^4.1.1", "@smithy/types": "^4.5.0", "@smithy/url-parser": "^4.1.1", "@smithy/util-middleware": "^4.1.1", @@ -4034,18 +4032,18 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.2.4.tgz", - "integrity": "sha512-amyqYQFewnAviX3yy/rI/n1HqAgfvUdkEhc04kDjxsngAUREKuOI24iwqQUirrj6GtodWmR4iO5Zeyl3/3BwWg==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.2.1.tgz", + "integrity": "sha512-JzfvjwSJXWRl7LkLgIRTUTd2Wj639yr3sQGpViGNEOjtb0AkAuYqRAHs+jSOI/LPC0ZTjmFVVtfrCICMuebexw==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.2.2", + "@smithy/node-config-provider": "^4.2.1", "@smithy/protocol-http": "^5.2.1", - "@smithy/service-error-classification": "^4.1.2", - "@smithy/smithy-client": "^4.6.3", + "@smithy/service-error-classification": "^4.1.1", + "@smithy/smithy-client": "^4.6.1", "@smithy/types": "^4.5.0", "@smithy/util-middleware": "^4.1.1", - "@smithy/util-retry": "^4.1.2", + "@smithy/util-retry": "^4.1.1", "@types/uuid": "^9.0.1", "tslib": "^2.6.2", "uuid": "^9.0.1" @@ -4082,13 +4080,13 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.2.2.tgz", - "integrity": "sha512-SYGTKyPvyCfEzIN5rD8q/bYaOPZprYUPD2f5g9M7OjaYupWOoQFYJ5ho+0wvxIRf471i2SR4GoiZ2r94Jq9h6A==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.2.1.tgz", + "integrity": "sha512-AIA0BJZq2h295J5NeCTKhg1WwtdTA/GqBCaVjk30bDgMHwniUETyh5cP9IiE9VrId7Kt8hS7zvREVMTv1VfA6g==", "license": "Apache-2.0", "dependencies": { "@smithy/property-provider": "^4.1.1", - "@smithy/shared-ini-file-loader": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.1.1", "@smithy/types": "^4.5.0", "tslib": "^2.6.2" }, @@ -4166,9 +4164,9 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.1.2.tgz", - "integrity": "sha512-Kqd8wyfmBWHZNppZSMfrQFpc3M9Y/kjyN8n8P4DqJJtuwgK1H914R471HTw7+RL+T7+kI1f1gOnL7Vb5z9+NgQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.1.1.tgz", + "integrity": "sha512-Iam75b/JNXyDE41UvrlM6n8DNOa/r1ylFyvgruTUx7h2Uk7vDNV9AAwP1vfL1fOL8ls0xArwEGVcGZVd7IO/Cw==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.5.0" @@ -4178,9 +4176,9 @@ } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.2.0.tgz", - "integrity": "sha512-OQTfmIEp2LLuWdxa8nEEPhZmiOREO6bcB6pjs0AySf4yiZhl6kMOfqmcwcY8BaBPX+0Tb+tG7/Ia/6mwpoZ7Pw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.1.1.tgz", + "integrity": "sha512-YkpikhIqGc4sfXeIbzSj10t2bJI/sSoP5qxLue6zG+tEE3ngOBSm8sO3+djacYvS/R5DfpxN/L9CyZsvwjWOAQ==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.5.0", @@ -4210,17 +4208,17 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.6.3.tgz", - "integrity": "sha512-K27LqywsaqKz4jusdUQYJh/YP2VbnbdskZ42zG8xfV+eovbTtMc2/ZatLWCfSkW0PDsTUXlpvlaMyu8925HsOw==", + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.6.1.tgz", + "integrity": "sha512-WolVLDb9UTPMEPPOncrCt6JmAMCSC/V2y5gst2STWJ5r7+8iNac+EFYQnmvDCYMfOLcilOSEpm5yXZXwbLak1Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.11.1", - "@smithy/middleware-endpoint": "^4.2.3", + "@smithy/core": "^3.11.0", + "@smithy/middleware-endpoint": "^4.2.1", "@smithy/middleware-stack": "^4.1.1", "@smithy/protocol-http": "^5.2.1", "@smithy/types": "^4.5.0", - "@smithy/util-stream": "^4.3.2", + "@smithy/util-stream": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -4317,13 +4315,13 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.1.3.tgz", - "integrity": "sha512-5fm3i2laE95uhY6n6O6uGFxI5SVbqo3/RWEuS3YsT0LVmSZk+0eUqPhKd4qk0KxBRPaT5VNT/WEBUqdMyYoRgg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.1.1.tgz", + "integrity": "sha512-hA1AKIHFUMa9Tl6q6y8p0pJ9aWHCCG8s57flmIyLE0W7HcJeYrYtnqXDcGnftvXEhdQnSexyegXnzzTGk8bKLA==", "license": "Apache-2.0", "dependencies": { "@smithy/property-provider": "^4.1.1", - "@smithy/smithy-client": "^4.6.3", + "@smithy/smithy-client": "^4.6.1", "@smithy/types": "^4.5.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -4333,16 +4331,16 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.1.3.tgz", - "integrity": "sha512-lwnMzlMslZ9GJNt+/wVjz6+fe9Wp5tqR1xAyQn+iywmP+Ymj0F6NhU/KfHM5jhGPQchRSCcau5weKhFdLIM4cA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.1.1.tgz", + "integrity": "sha512-RGSpmoBrA+5D2WjwtK7tto6Pc2wO9KSXKLpLONhFZ8VyuCbqlLdiDAfuDTNY9AJe4JoE+Cx806cpTQQoQ71zPQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/config-resolver": "^4.2.2", - "@smithy/credential-provider-imds": "^4.1.2", - "@smithy/node-config-provider": "^4.2.2", + "@smithy/config-resolver": "^4.2.1", + "@smithy/credential-provider-imds": "^4.1.1", + "@smithy/node-config-provider": "^4.2.1", "@smithy/property-provider": "^4.1.1", - "@smithy/smithy-client": "^4.6.3", + "@smithy/smithy-client": "^4.6.1", "@smithy/types": "^4.5.0", "tslib": "^2.6.2" }, @@ -4351,12 +4349,12 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.1.2.tgz", - "integrity": "sha512-+AJsaaEGb5ySvf1SKMRrPZdYHRYSzMkCoK16jWnIMpREAnflVspMIDeCVSZJuj+5muZfgGpNpijE3mUNtjv01Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.1.1.tgz", + "integrity": "sha512-qB4R9kO0SetA11Rzu6MVGFIaGYX3p6SGGGfWwsKnC6nXIf0n/0AKVwRTsYsz9ToN8CeNNtNgQRwKFBndGJZdyw==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.2.2", + "@smithy/node-config-provider": "^4.2.1", "@smithy/types": "^4.5.0", "tslib": "^2.6.2" }, @@ -4390,12 +4388,12 @@ } }, "node_modules/@smithy/util-retry": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.1.2.tgz", - "integrity": "sha512-NCgr1d0/EdeP6U5PSZ9Uv5SMR5XRRYoVr1kRVtKZxWL3tixEL3UatrPIMFZSKwHlCcp2zPLDvMubVDULRqeunA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.1.1.tgz", + "integrity": "sha512-jGeybqEZ/LIordPLMh5bnmnoIgsqnp4IEimmUp5c5voZ8yx+5kAlN5+juyr7p+f7AtZTgvhmInQk4Q0UVbrZ0Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^4.1.2", + "@smithy/service-error-classification": "^4.1.1", "@smithy/types": "^4.5.0", "tslib": "^2.6.2" }, @@ -4404,9 +4402,9 @@ } }, "node_modules/@smithy/util-stream": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.3.2.tgz", - "integrity": "sha512-Ka+FA2UCC/Q1dEqUanCdpqwxOFdf5Dg2VXtPtB1qxLcSGh5C1HdzklIt18xL504Wiy9nNUKwDMRTVCbKGoK69g==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.3.1.tgz", + "integrity": "sha512-khKkW/Jqkgh6caxMWbMuox9+YfGlsk9OnHOYCGVEdYQb/XVzcORXHLYUubHmmda0pubEDncofUrPNniS9d+uAA==", "license": "Apache-2.0", "dependencies": { "@smithy/fetch-http-handler": "^5.2.1", @@ -4910,9 +4908,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.18.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.6.tgz", - "integrity": "sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==", + "version": "22.18.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.3.tgz", + "integrity": "sha512-gTVM8js2twdtqM+AE2PdGEe9zGQY4UvmFjan9rZcVb6FGdStfjWoWejdmy4CfWVO9rh5MiYQGZloKAGkJt8lMw==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -5425,9 +5423,9 @@ } }, "node_modules/@vavite/multibuild/node_modules/@types/node": { - "version": "18.19.127", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.127.tgz", - "integrity": "sha512-gSjxjrnKXML/yo0BO099uPixMqfpJU0TKYjpfLU7TrtA2WWDki412Np/RSTPRil1saKBhvVVKzVx/p/6p94nVA==", + "version": "18.19.124", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.124.tgz", + "integrity": "sha512-hY4YWZFLs3ku6D2Gqo3RchTd9VRCcrjqp/I0mmohYeUVA5Y8eCXKJEasHxLAJVZRJuQogfd1GiJ9lgogBgKeuQ==", "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -6241,9 +6239,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", - "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.1.tgz", + "integrity": "sha512-Kn4kbSXpkFHCGE6rBFNwIv0GQs4AvDT80jlveJDKFxjbTYMUeB4QtsdPCv6H8Cm19Je7IU6VFtRl2zWZI0rudQ==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -6277,9 +6275,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.6.tgz", - "integrity": "sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.2.tgz", + "integrity": "sha512-NvcIedLxrs9llVpX7wI+Jz4Hn9vJQkCPKrTaHIE0sW/Rj1iq6Fzby4NbyTZjQJNoypBXNaG7tEHkTgONZpwgxQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -6534,9 +6532,9 @@ } }, "node_modules/browserslist": { - "version": "4.26.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz", - "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==", + "version": "4.26.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.0.tgz", + "integrity": "sha512-P9go2WrP9FiPwLv3zqRD/Uoxo0RSHjzFCiQz7d4vbmwNqQFo9T9WCeP/Qn5EbcKQY6DBbkxEXNcpJOmncNrb7A==", "dev": true, "funding": [ { @@ -6554,7 +6552,7 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.8.3", + "baseline-browser-mapping": "^2.8.2", "caniuse-lite": "^1.0.30001741", "electron-to-chromium": "^1.5.218", "node-releases": "^2.0.21", @@ -6698,9 +6696,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001743", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001743.tgz", - "integrity": "sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==", + "version": "1.0.30001741", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001741.tgz", + "integrity": "sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==", "dev": true, "funding": [ { @@ -7399,6 +7397,7 @@ "version": "4.6.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "dev": true, "license": "MIT", "engines": { "node": "*" @@ -7411,9 +7410,9 @@ "license": "MIT" }, "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -7621,9 +7620,9 @@ } }, "node_modules/detect-libc": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.0.tgz", - "integrity": "sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "license": "Apache-2.0", "engines": { "node": ">=8" @@ -7867,9 +7866,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.222", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.222.tgz", - "integrity": "sha512-gA7psSwSwQRE60CEoLz6JBCQPIxNeuzB2nL8vE03GK/OHxlvykbLyeiumQy1iH5C2f3YbRAZpGCMT12a/9ih9w==", + "version": "1.5.218", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.218.tgz", + "integrity": "sha512-uwwdN0TUHs8u6iRgN8vKeWZMRll4gBkz+QMqdS7DDe49uiK68/UX92lFb61oiFPrpYZNeZIqa4bA7O6Aiasnzg==", "dev": true, "license": "ISC" }, @@ -7904,6 +7903,7 @@ "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, "license": "MIT", "dependencies": { "once": "^1.4.0" @@ -7971,9 +7971,9 @@ } }, "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "license": "MIT", "dependencies": { @@ -8041,9 +8041,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", - "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -8053,32 +8053,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.10", - "@esbuild/android-arm": "0.25.10", - "@esbuild/android-arm64": "0.25.10", - "@esbuild/android-x64": "0.25.10", - "@esbuild/darwin-arm64": "0.25.10", - "@esbuild/darwin-x64": "0.25.10", - "@esbuild/freebsd-arm64": "0.25.10", - "@esbuild/freebsd-x64": "0.25.10", - "@esbuild/linux-arm": "0.25.10", - "@esbuild/linux-arm64": "0.25.10", - "@esbuild/linux-ia32": "0.25.10", - "@esbuild/linux-loong64": "0.25.10", - "@esbuild/linux-mips64el": "0.25.10", - "@esbuild/linux-ppc64": "0.25.10", - "@esbuild/linux-riscv64": "0.25.10", - "@esbuild/linux-s390x": "0.25.10", - "@esbuild/linux-x64": "0.25.10", - "@esbuild/netbsd-arm64": "0.25.10", - "@esbuild/netbsd-x64": "0.25.10", - "@esbuild/openbsd-arm64": "0.25.10", - "@esbuild/openbsd-x64": "0.25.10", - "@esbuild/openharmony-arm64": "0.25.10", - "@esbuild/sunos-x64": "0.25.10", - "@esbuild/win32-arm64": "0.25.10", - "@esbuild/win32-ia32": "0.25.10", - "@esbuild/win32-x64": "0.25.10" + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" } }, "node_modules/escalade": { @@ -8559,6 +8559,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", + "dev": true, "license": "MIT" }, "node_modules/fast-deep-equal": { @@ -8631,6 +8632,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, "license": "MIT" }, "node_modules/fast-uri": { @@ -9137,9 +9139,9 @@ } }, "node_modules/fs-extra": { - "version": "11.3.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", - "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", + "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -9524,9 +9526,9 @@ } }, "node_modules/got": { - "version": "14.4.9", - "resolved": "https://registry.npmjs.org/got/-/got-14.4.9.tgz", - "integrity": "sha512-Dbu075Jwm3QwNCIoCenqkqY8l2gd7e/TanuhMbzZIEsb1mpAneImSusKhZ+XdqqC3S91SDV/1SdWpGXKAlm8tA==", + "version": "14.4.8", + "resolved": "https://registry.npmjs.org/got/-/got-14.4.8.tgz", + "integrity": "sha512-vxwU4HuR0BIl+zcT1LYrgBjM+IJjNElOjCzs0aPgHorQyr/V6H6Y73Sn3r3FOlUffvWD+Q5jtRuGWaXkU8Jbhg==", "license": "MIT", "dependencies": { "@sindresorhus/is": "^7.0.1", @@ -9664,6 +9666,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "dev": true, "license": "MIT" }, "node_modules/hookable": { @@ -10237,9 +10240,9 @@ } }, "node_modules/is-network-error": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.0.tgz", - "integrity": "sha512-6oIwpsgRfnDiyEDLMay/GqCl3HoAtH5+RUKW29gYkL0QA+ipzpDLA16yQs7/RHCSu+BwgbJaOUqa4A99qNVQVw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", "dev": true, "license": "MIT", "engines": { @@ -10428,6 +10431,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -10961,9 +10965,9 @@ } }, "node_modules/memfs": { - "version": "4.42.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.42.0.tgz", - "integrity": "sha512-RG+4HMGyIVp6UWDWbFmZ38yKrSzblPnfJu0PyPt0hw52KW4PPlPp+HdV4qZBG0hLDuYVnf8wfQT4NymKXnlQjA==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.39.0.tgz", + "integrity": "sha512-tFRr2IkSXl2B6IAJsxjHIMTOsfLt9W+8+t2uNxCeQcz4tFqgQR8DYk8hlLH2HsucTctLuoHq3U0G08atyBE3yw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -11154,6 +11158,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -11711,15 +11716,15 @@ } }, "node_modules/p-limit": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.1.1.tgz", - "integrity": "sha512-i8PyM2JnsNChVSYWLr2BAjNoLi0BAYC+wecOnZnVV+YSNJkzP7cWmvI34dk0WArWfH9KwBHNoZI3P3MppImlIA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "license": "MIT", "dependencies": { - "yocto-queue": "^1.2.1" + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">=20" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -11740,21 +11745,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-map": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", @@ -12140,9 +12130,9 @@ } }, "node_modules/pino": { - "version": "9.10.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-9.10.0.tgz", - "integrity": "sha512-VOFxoNnxICtxaN8S3E73pR66c5MTFC+rwRcNRyHV/bV/c90dXvJqMfjkeRFsGBDXmlUN3LccJQPqGIufnaJePA==", + "version": "9.9.5", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.9.5.tgz", + "integrity": "sha512-d1s98p8/4TfYhsJ09r/Azt30aYELRi6NNnZtEbqFw6BoGsdPVf5lKNK3kUwH8BmJJfpTLNuicjUQjaMbd93dVg==", "license": "MIT", "dependencies": { "atomic-sleep": "^1.0.0", @@ -12174,6 +12164,7 @@ "version": "13.1.1", "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.1.tgz", "integrity": "sha512-TNNEOg0eA0u+/WuqH0MH0Xui7uqVk9D74ESOpjtebSQYbNWJk/dIxCXIxFsNfeN53JmtWqYHP2OrIZjT/CBEnA==", + "dev": true, "license": "MIT", "dependencies": { "colorette": "^2.0.7", @@ -12198,6 +12189,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.0.0.tgz", "integrity": "sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA==", + "dev": true, "funding": [ { "type": "github", @@ -12214,6 +12206,7 @@ "version": "5.0.3", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.16" @@ -12319,20 +12312,10 @@ } }, "node_modules/postcss-js": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", - "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", "dependencies": { "camelcase-css": "^2.0.1" @@ -12340,6 +12323,10 @@ "engines": { "node": "^12 || ^14 || >= 16" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, "peerDependencies": { "postcss": "^8.4.21" } @@ -12588,9 +12575,9 @@ } }, "node_modules/pretty-ms": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", - "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz", + "integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -12665,6 +12652,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dev": true, "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -13166,9 +13154,9 @@ "license": "MIT" }, "node_modules/rollup": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.51.0.tgz", - "integrity": "sha512-7cR0XWrdp/UAj2HMY/Y4QQEUjidn3l2AY1wSeZoFjMbD8aOMPoV9wgTFYbrJpPzzvejDEini1h3CiUP8wLzxQA==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz", + "integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==", "license": "MIT", "dependencies": { "@types/estree": "1.0.8" @@ -13181,27 +13169,27 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.51.0", - "@rollup/rollup-android-arm64": "4.51.0", - "@rollup/rollup-darwin-arm64": "4.51.0", - "@rollup/rollup-darwin-x64": "4.51.0", - "@rollup/rollup-freebsd-arm64": "4.51.0", - "@rollup/rollup-freebsd-x64": "4.51.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.51.0", - "@rollup/rollup-linux-arm-musleabihf": "4.51.0", - "@rollup/rollup-linux-arm64-gnu": "4.51.0", - "@rollup/rollup-linux-arm64-musl": "4.51.0", - "@rollup/rollup-linux-loong64-gnu": "4.51.0", - "@rollup/rollup-linux-ppc64-gnu": "4.51.0", - "@rollup/rollup-linux-riscv64-gnu": "4.51.0", - "@rollup/rollup-linux-riscv64-musl": "4.51.0", - "@rollup/rollup-linux-s390x-gnu": "4.51.0", - "@rollup/rollup-linux-x64-gnu": "4.51.0", - "@rollup/rollup-linux-x64-musl": "4.51.0", - "@rollup/rollup-openharmony-arm64": "4.51.0", - "@rollup/rollup-win32-arm64-msvc": "4.51.0", - "@rollup/rollup-win32-ia32-msvc": "4.51.0", - "@rollup/rollup-win32-x64-msvc": "4.51.0", + "@rollup/rollup-android-arm-eabi": "4.50.1", + "@rollup/rollup-android-arm64": "4.50.1", + "@rollup/rollup-darwin-arm64": "4.50.1", + "@rollup/rollup-darwin-x64": "4.50.1", + "@rollup/rollup-freebsd-arm64": "4.50.1", + "@rollup/rollup-freebsd-x64": "4.50.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.50.1", + "@rollup/rollup-linux-arm-musleabihf": "4.50.1", + "@rollup/rollup-linux-arm64-gnu": "4.50.1", + "@rollup/rollup-linux-arm64-musl": "4.50.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.50.1", + "@rollup/rollup-linux-ppc64-gnu": "4.50.1", + "@rollup/rollup-linux-riscv64-gnu": "4.50.1", + "@rollup/rollup-linux-riscv64-musl": "4.50.1", + "@rollup/rollup-linux-s390x-gnu": "4.50.1", + "@rollup/rollup-linux-x64-gnu": "4.50.1", + "@rollup/rollup-linux-x64-musl": "4.50.1", + "@rollup/rollup-openharmony-arm64": "4.50.1", + "@rollup/rollup-win32-arm64-msvc": "4.50.1", + "@rollup/rollup-win32-ia32-msvc": "4.50.1", + "@rollup/rollup-win32-x64-msvc": "4.50.1", "fsevents": "~2.3.2" } }, diff --git a/package.json b/package.json index 49385ba..989a29e 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "hot-hook": "^0.4.0", "numeral": "^2.0.6", "pinia": "^3.0.2", + "pino-pretty": "^13.0.0", "postcss-loader": "^8.1.1", "prettier": "^3.4.2", "supertest": "^6.3.3", @@ -114,9 +115,7 @@ "node-2fa": "^2.0.3", "node-exceptions": "^4.0.1", "notiwind": "^2.0.0", - "p-limit": "^7.1.1", "pg": "^8.9.0", - "pino-pretty": "^13.0.0", "qrcode": "^1.5.3", "redis": "^5.0.0", "reflect-metadata": "^0.2.1", diff --git a/providers/vinejs_provider.ts b/providers/vinejs_provider.ts index 568dd3e..e4aad4c 100644 --- a/providers/vinejs_provider.ts +++ b/providers/vinejs_provider.ts @@ -6,16 +6,17 @@ import type { ApplicationService } from '@adonisjs/core/types'; import vine, { symbols, BaseLiteralType, Vine } from '@vinejs/vine'; import type { FieldContext, FieldOptions } from '@vinejs/vine/types'; +// import type { MultipartFile, FileValidationOptions } from '@adonisjs/bodyparser/types'; import type { MultipartFile } from '@adonisjs/core/bodyparser'; import type { FileValidationOptions } from '@adonisjs/core/types/bodyparser'; import { Request, RequestValidator } from '@adonisjs/core/http'; import MimeType from '#models/mime_type'; + /** * Validation options accepted by the "file" rule */ export type FileRuleValidationOptions = Partial | ((field: FieldContext) => Partial); - /** * Extend VineJS */ @@ -24,7 +25,6 @@ declare module '@vinejs/vine' { myfile(options?: FileRuleValidationOptions): VineMultipartFile; } } - /** * Extend HTTP request class */ @@ -36,54 +36,19 @@ declare module '@adonisjs/core/http' { * Checks if the value is an instance of multipart file * from bodyparser. */ -export function isBodyParserFile(file: MultipartFile | unknown): file is MultipartFile { +export function isBodyParserFile(file: MultipartFile | unknown): boolean { return !!(file && typeof file === 'object' && 'isMultipartFile' in file); } +export async function getEnabledExtensions() { + const enabledExtensions = await MimeType.query().select('file_extension').where('enabled', true).exec(); + const extensions = enabledExtensions + .map((extension) => { + return extension.file_extension.split('|'); + }) + .flat(); -/** - * Cache for enabled extensions to reduce database queries - */ -let extensionsCache: string[] | null = null; -let cacheTimestamp = 0; -const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes - -/** - * Get enabled extensions with caching - */ -export async function getEnabledExtensions(): Promise { - const now = Date.now(); - - if (extensionsCache && now - cacheTimestamp < CACHE_DURATION) { - return extensionsCache; - } - - try { - const enabledExtensions = await MimeType.query().select('file_extension').where('enabled', true).exec(); - - const extensions = enabledExtensions - .map((extension) => extension.file_extension.split('|')) - .flat() - .map((ext) => ext.toLowerCase().trim()) - .filter((ext) => ext.length > 0); - - extensionsCache = [...new Set(extensions)]; // Remove duplicates - cacheTimestamp = now; - - return extensionsCache; - } catch (error) { - console.error('Error fetching enabled extensions:', error); - return extensionsCache || []; - } + return extensions; } - -/** - * Clear extensions cache - */ -export function clearExtensionsCache(): void { - extensionsCache = null; - cacheTimestamp = 0; -} - /** * VineJS validation rule that validates the file to be an * instance of BodyParser MultipartFile class. @@ -100,7 +65,6 @@ const isMultipartFile = vine.createRule(async (file: MultipartFile | unknown, op // At this point, you can use type assertion to explicitly tell TypeScript that file is of type MultipartFile const validatedFile = file as MultipartFile; const validationOptions = typeof options === 'function' ? options(field) : options; - /** * Set size when it's defined in the options and missing * on the file instance @@ -108,29 +72,30 @@ const isMultipartFile = vine.createRule(async (file: MultipartFile | unknown, op if (validatedFile.sizeLimit === undefined && validationOptions.size) { validatedFile.sizeLimit = validationOptions.size; } - /** * Set extensions when it's defined in the options and missing * on the file instance */ - if (validatedFile.allowedExtensions === undefined) { - if (validationOptions.extnames !== undefined) { - validatedFile.allowedExtensions = validationOptions.extnames; - } else { - validatedFile.allowedExtensions = await getEnabledExtensions(); - } + // if (validatedFile.allowedExtensions === undefined && validationOptions.extnames) { + // validatedFile.allowedExtensions = validationOptions.extnames; + // } + if (validatedFile.allowedExtensions === undefined && validationOptions.extnames !== undefined) { + validatedFile.allowedExtensions = validationOptions.extnames; // await getEnabledExtensions(); + } else if (validatedFile.allowedExtensions === undefined && validationOptions.extnames === undefined) { + validatedFile.allowedExtensions = await getEnabledExtensions(); } - + /** + * wieder lΓΆschen + * Set extensions when it's defined in the options and missing + * on the file instance + */ + // if (file.clientNameSizeLimit === undefined && validationOptions.clientNameSizeLimit) { + // file.clientNameSizeLimit = validationOptions.clientNameSizeLimit; + // } /** * Validate file */ - try { - validatedFile.validate(); - } catch (error) { - field.report(`File validation failed: ${error.message}`, 'file.validation_error', field, validationOptions); - return; - } - + validatedFile.validate(); /** * Report errors */ @@ -142,37 +107,36 @@ const isMultipartFile = vine.createRule(async (file: MultipartFile | unknown, op const MULTIPART_FILE: typeof symbols.SUBTYPE = symbols.SUBTYPE; export class VineMultipartFile extends BaseLiteralType { + [MULTIPART_FILE]: string; - public validationOptions?: FileRuleValidationOptions; + // constructor(validationOptions?: FileRuleValidationOptions, options?: FieldOptions) { + // super(options, [isMultipartFile(validationOptions || {})]); + // this.validationOptions = validationOptions; + // this.#private = true; + // } + + // clone(): this { + // return new VineMultipartFile(this.validationOptions, this.cloneOptions()) as this; + // } + // #private; + // constructor(validationOptions?: FileRuleValidationOptions, options?: FieldOptions, validations?: Validation[]); + // clone(): this; + + public validationOptions; // extnames: (18) ['gpkg', 'htm', 'html', 'csv', 'txt', 'asc', 'c', 'cc', 'h', 'srt', 'tiff', 'pdf', 'png', 'zip', 'jpg', 'jpeg', 'jpe', 'xlsx'] // size: '512mb' + // public constructor(validationOptions?: FileRuleValidationOptions, options?: FieldOptions, validations?: Validation[]) { public constructor(validationOptions?: FileRuleValidationOptions, options?: FieldOptions) { + // super(options, validations); super(options, [isMultipartFile(validationOptions || {})]); this.validationOptions = validationOptions; } public clone(): any { + // return new VineMultipartFile(this.validationOptions, this.cloneOptions(), this.cloneValidations()); return new VineMultipartFile(this.validationOptions, this.cloneOptions()); } - - /** - * Set maximum file size - */ - public maxSize(size: string | number): this { - const newOptions = { ...this.validationOptions, size }; - return new VineMultipartFile(newOptions, this.cloneOptions()) as this; - } - - /** - * Set allowed extensions - */ - public extensions(extnames: string[]): this { - const newOptions = { ...this.validationOptions, extnames }; - return new VineMultipartFile(newOptions, this.cloneOptions()) as this; - } - - } export default class VinejsProvider { @@ -191,8 +155,13 @@ export default class VinejsProvider { /** * The container bindings have booted */ + boot(): void { - Vine.macro('myfile', function (this: Vine, options?: FileRuleValidationOptions) { + // VineString.macro('translatedLanguage', function (this: VineString, options: Options) { + // return this.use(translatedLanguageRule(options)); + // }); + + Vine.macro('myfile', function (this: Vine, options) { return new VineMultipartFile(options); }); @@ -206,41 +175,6 @@ export default class VinejsProvider { } return new RequestValidator(this.ctx).validateUsing(...args); }); - - // Ensure MIME validation macros are loaded - this.loadMimeValidationMacros(); - this.loadFileScanMacros(); - this.loadFileLengthMacros(); - } - - /** - * Load MIME validation macros - called during boot to ensure they're available - */ - private async loadMimeValidationMacros(): Promise { - try { - // Dynamically import the MIME validation rule to ensure macros are registered - await import('#start/rules/allowed_extensions_mimetypes'); - } catch (error) { - console.warn('Could not load MIME validation macros:', error); - } - } - - private async loadFileScanMacros(): Promise { - try { - // Dynamically import the MIME validation rule to ensure macros are registered - await import('#start/rules/file_scan'); - } catch (error) { - console.warn('Could not load MIME validation macros:', error); - } - } - - private async loadFileLengthMacros(): Promise { - try { - // Dynamically import the MIME validation rule to ensure macros are registered - await import('#start/rules/file_length'); - } catch (error) { - console.warn('Could not load MIME validation macros:', error); - } } /** @@ -256,7 +190,5 @@ export default class VinejsProvider { /** * Preparing to shutdown the app */ - async shutdown() { - clearExtensionsCache(); - } + async shutdown() {} } diff --git a/readme.md b/readme.md index 7d032ce..0fd7e64 100644 --- a/readme.md +++ b/readme.md @@ -11,8 +11,6 @@ Welcome to the Tethys Research Repository Backend System! This is the backend co - [Configuration](#configuration) - [Database](#database) - [API Documentation](#api-documentation) -- [Commands](#commands) -- [Documentation](#documentation) - [Contributing](#contributing) - [License](#license) @@ -31,175 +29,5 @@ Before you begin, ensure you have met the following requirements: 1. Clone this repository: ```bash - git clone git clone https://gitea.geologie.ac.at/geolba/tethys.backend.git - cd tethys-backend + git clone https://gitea.geologie.ac.at/geolba/tethys.backend.git ``` - -2. Install dependencies: - - ```bash - npm install - ``` - -3. Configure environment variables (see [Configuration](#configuration)) - -4. Run database migrations: - - ```bash - node ace migration:run - ``` - -5. Start the development server: - - ```bash - npm run dev - ``` - -## Usage - -The Tethys Backend provides RESTful APIs for managing research datasets, user authentication, DOI registration, and search functionality. - -## Configuration - -Copy the `.env.example` file to `.env` and configure the following variables: - -### Database Configuration -```bash -DB_CONNECTION=pg -DB_HOST=localhost -DB_PORT=5432 -DB_USER=your_username -DB_PASSWORD=your_password -DB_DATABASE=tethys_db -``` - -### DataCite Configuration -```bash -# DataCite Credentials -DATACITE_USERNAME=your_datacite_username -DATACITE_PASSWORD=your_datacite_password -DATACITE_PREFIX=10.21388 - -# Environment-specific API endpoints -DATACITE_API_URL=https://api.test.datacite.org # Test environment -DATACITE_SERVICE_URL=https://mds.test.datacite.org # Test MDS - -# For production: -# DATACITE_API_URL=https://api.datacite.org -# DATACITE_SERVICE_URL=https://mds.datacite.org -``` - -### OpenSearch Configuration -```bash -OPENSEARCH_HOST=localhost:9200 -``` - -### Application Configuration -```bash -BASE_DOMAIN=tethys.at -APP_KEY=your_app_key -``` - -## Database - -The system uses PostgreSQL with Lucid ORM. Key models include: - -- **Dataset**: Research dataset metadata -- **DatasetIdentifier**: DOI and other identifiers for datasets -- **User**: User management and authentication -- **XmlCache**: Cached XML metadata - -Run migrations and seeders: - -```bash -# Run migrations -node ace migration:run - -# Run seeders (if available) -node ace db:seed -``` - -## API Documentation - -API endpoints are available for: - -- Dataset management (`/api/datasets`) -- User authentication (`/api/auth`) -- DOI registration (`/api/doi`) -- Search functionality (`/api/search`) - -*Detailed API documentation can be found in the `/docs/api` directory.* - -## Commands - -The system includes several Ace commands for maintenance and data management: - -### Dataset Indexing -```bash -# Index all published datasets to OpenSearch -node ace index:datasets - -# Index a specific dataset -node ace index:datasets --publish_id 123 -``` - -### DataCite DOI Management -```bash -# Update DataCite records for modified datasets -node ace update:datacite - -# Show detailed statistics for datasets needing updates -node ace update:datacite --stats - -# Preview what would be updated (dry run) -node ace update:datacite --dry-run - -# Force update all DOI records -node ace update:datacite --force - -# Update a specific dataset -node ace update:datacite --publish_id 123 -``` - -*For detailed command documentation, see the [Commands Documentation](docs/commands/)* - -## Documentation - -Comprehensive documentation is available in the `/docs` directory: - -- **[Commands Documentation](docs/commands/)** - Detailed guides for Ace commands - - [DataCite Update Command](docs/commands/update-datacite.md) - DOI synchronization and management - - [Dataset Indexing Command](docs/commands/index-datasets.md) - Search index management -- **[API Documentation](docs/api/)** - REST API endpoints and usage -- **[Deployment Guide](docs/deployment/)** - Production deployment instructions -- **[Configuration Guide](docs/configuration/)** - Environment setup and configuration options - -## Contributing - -1. Fork the repository -2. Create a feature branch (`git checkout -b feature/amazing-feature`) -3. Commit your changes (`git commit -m 'Add some amazing feature'`) -4. Push to the branch (`git push origin feature/amazing-feature`) -5. Open a Pull Request - -### Development Guidelines - -- Follow the existing code style and conventions -- Write tests for new features -- Update documentation for any API changes -- Ensure all commands and migrations work properly - -### Testing Commands - -```bash -# Run tests -npm test - -# Test specific commands -node ace update:datacite --dry-run --publish_id 123 -node ace index:datasets --publish_id 123 -``` - -## License - -This project is licensed under the [MIT License](LICENSE). \ No newline at end of file diff --git a/resources/js/Pages/Editor/Dataset/Edit.vue b/resources/js/Pages/Editor/Dataset/Edit.vue index 9a2385c..e33e5dd 100644 --- a/resources/js/Pages/Editor/Dataset/Edit.vue +++ b/resources/js/Pages/Editor/Dataset/Edit.vue @@ -163,7 +163,7 @@ - - { - router.get('clients', [UserController, 'getSubmitters']).as('client.index').use(middleware.auth()); - router.get('authors', [AuthorsController, 'index']).as('author.index').use(middleware.auth()); + router.get('clients', [UserController, 'getSubmitters']).as('client.index').use(middleware.auth());; + router.get('authors', [AuthorsController, 'index']).as('author.index').use(middleware.auth());; router.get('datasets', [DatasetController, 'index']).as('dataset.index'); router.get('persons', [AuthorsController, 'persons']).as('author.persons'); - // This should come BEFORE any other routes that might conflict - router - .get('/dataset/:prefix/:value', [DatasetController, 'findByIdentifier']) - .where('prefix', /^10\.\d+$/) // Match DOI prefix pattern (10.xxxx) - .where('value', /^[a-zA-Z0-9._-]+\.[0-9]+(?:\.[0-9]+)*$/) // Match DOI suffix pattern - .as('dataset.findByIdentifier'); - router.get('/dataset', [DatasetController, 'findAll']).as('dataset.findAll'); router.get('/dataset/:publish_id', [DatasetController, 'findOne']).as('dataset.findOne'); router.get('/sitelinks/:year', [HomeController, 'findDocumentsPerYear']); @@ -45,7 +35,7 @@ router .as('apps.twofactor_backupcodes.create') .use(middleware.auth()); - router.get('collections/:id', [CollectionsController, 'show']).as('collection.show'); + router.get('collections/:id', [CollectionsController, 'show']).as('collection.show') }) // .namespace('App/Controllers/Http/Api') .prefix('api'); diff --git a/start/rules/orcid.ts b/start/rules/orcid.ts index b16e504..ee60534 100644 --- a/start/rules/orcid.ts +++ b/start/rules/orcid.ts @@ -1,7 +1,7 @@ /* |-------------------------------------------------------------------------- | Preloaded File - node ace make:preload rules/orcid -| Do you want to register the preload file in .adonisrc.ts file? (y/N) Β· true +| ❯ Do you want to register the preload file in .adonisrc.ts file? (y/N) Β· true | DONE: create start/rules/orcid.ts | DONE: update adonisrc.ts file |--------------------------------------------------------------------------