diff --git a/codecov.yml b/codecov.yml index acb9b1e20..96cf37378 100644 --- a/codecov.yml +++ b/codecov.yml @@ -2,7 +2,7 @@ coverage: status: project: default: - target: 67% + target: 68% threshold: 1% patch: default: diff --git a/imports/_test/fixtures.ts b/imports/_test/fixtures.ts index f65648c23..877d38fa7 100644 --- a/imports/_test/fixtures.ts +++ b/imports/_test/fixtures.ts @@ -3,10 +3,14 @@ import 'regenerator-runtime/runtime.js'; import {assert, expect} from 'chai'; +import {Meteor} from 'meteor/meteor'; + import {cleanup as unmount} from '@testing-library/react'; import totalOrder from 'total-order'; import {sorted} from '@iterable-iterator/sorted'; +// eslint-disable-next-line import/no-unassigned-import +import '../api/endpoint/_dev/_disableRateLimiting'; import logout from '../api/user/logout'; import invoke from '../api/endpoint/invoke'; import call from '../api/endpoint/call'; @@ -174,11 +178,24 @@ export const dropId = ({_id, ...rest}) => { export const dropIds = (x) => x.map(dropId); -export const create = (template, extra) => { - if (typeof template === 'function') return extra ?? template(); +export const dropOwner = ({owner, ...rest}) => { + assert(typeof owner === 'string'); + return rest; +}; + +export const dropOwners = (x) => x.map(dropOwner); + +export const create = (template, extra, hasExtra: boolean) => { + if (typeof template === 'function') return hasExtra ? extra : template(); if (Array.isArray(template)) { return template - .map((x, i) => create(x, extra?.[i])) + .map((x, i) => + create( + x, + extra?.[i], + Object.prototype.hasOwnProperty.call(extra ?? [], i), + ), + ) .concat(extra?.slice(template.length) ?? []); } @@ -186,7 +203,11 @@ export const create = (template, extra) => { (extra === undefined ? [] : Object.entries(extra)).concat( Object.entries(template).map(([key, value]) => [ key, - create(value, extra?.[key]), + create( + value, + extra?.[key], + Object.prototype.hasOwnProperty.call(extra ?? {}, key), + ), ]), ), ); @@ -204,4 +225,5 @@ export const findOneOrThrow = async ( return result!; }; -export const makeTemplate = (template) => (extra?) => create(template, extra); +export const makeTemplate = (template) => (extra?) => + create(template, extra, extra !== undefined); diff --git a/imports/api/ObserveSequenceChangesCallbacks.ts b/imports/api/ObserveSequenceChangesCallbacks.ts new file mode 100644 index 000000000..8b3bec5ca --- /dev/null +++ b/imports/api/ObserveSequenceChangesCallbacks.ts @@ -0,0 +1,8 @@ +import {type Mongo} from 'meteor/mongo'; + +type ObserveSequenceChangesCallbacks = Pick< + Mongo.ObserveChangesCallbacks, + 'addedBefore' | 'movedBefore' | 'changed' | 'removed' +>; + +export default ObserveSequenceChangesCallbacks; diff --git a/imports/api/ObserveSetChangesCallbacks.ts b/imports/api/ObserveSetChangesCallbacks.ts new file mode 100644 index 000000000..458b2cef6 --- /dev/null +++ b/imports/api/ObserveSetChangesCallbacks.ts @@ -0,0 +1,8 @@ +import {type Mongo} from 'meteor/mongo'; + +type ObserveSetChangesCallbacks = Pick< + Mongo.ObserveChangesCallbacks, + 'added' | 'changed' | 'removed' +>; + +export default ObserveSetChangesCallbacks; diff --git a/imports/api/appointments.ts b/imports/api/appointments.ts index c24d584aa..fa1a29c35 100644 --- a/imports/api/appointments.ts +++ b/imports/api/appointments.ts @@ -61,8 +61,8 @@ export const appointmentUpdate = schema.union([ schema.object({ patient: schema.object({ _id: schema.string(), - firstname: schema.string(), - lastname: schema.string(), + firstname: schema.string().optional(), + lastname: schema.string().optional(), }), phone: schema.string().optional(), datetime: schema.date().optional(), diff --git a/imports/api/collection/define.ts b/imports/api/collection/define.ts index 482362ca4..45943a7b7 100644 --- a/imports/api/collection/define.ts +++ b/imports/api/collection/define.ts @@ -1,11 +1,21 @@ +import assert from 'assert'; + import type Document from '../Document'; import Collection from '../Collection'; +import {hasCollection, addCollection} from './registry'; + const define = (name: string) => { - return new Collection(name, { + assert(!hasCollection(name)); + + const collection = new Collection(name, { idGeneration: 'STRING', defineMutationMethods: false, }); + + addCollection(name, collection); + + return collection; }; export default define; diff --git a/imports/api/collection/registry.ts b/imports/api/collection/registry.ts new file mode 100644 index 000000000..a2c388738 --- /dev/null +++ b/imports/api/collection/registry.ts @@ -0,0 +1,26 @@ +import assert from 'assert'; + +import type Document from '../Document'; +import type Collection from '../Collection'; + +const _registry = new Map>(); + +export const getCollection = ( + name: string, +): Collection => { + const collection = _registry.get(name); + assert(collection !== undefined); + return collection; +}; + +export const hasCollection = (name: string) => { + return _registry.has(name); +}; + +export const addCollection = ( + name: string, + collection: Collection, +) => { + assert(!hasCollection(name)); + _registry.set(name, collection); +}; diff --git a/imports/api/consultations.ts b/imports/api/consultations.ts index 9f33058e1..1e453f699 100644 --- a/imports/api/consultations.ts +++ b/imports/api/consultations.ts @@ -32,6 +32,7 @@ import findOneSync from './publication/findOneSync'; import type Selector from './query/Selector'; import {type AuthenticatedContext} from './publication/Context'; import {type DocumentUpdate} from './DocumentUpdate'; +import observeSetChanges from './query/observeSetChanges'; export const DEFAULT_DURATION_IN_MINUTES = 15; export const DEFAULT_DURATION_IN_SECONDS = DEFAULT_DURATION_IN_MINUTES * 60; @@ -127,18 +128,18 @@ export const filterBookPrefill = () => ({ }, }); -export function setupConsultationsStatsPublication( +export async function setupConsultationsStatsPublication( this: AuthenticatedContext, collectionName: string, filter: Filter, ) { // Generate unique key depending on parameters const key = statsKey(filter); - const selector = { + const scopedFilter = { ...filter, isDone: true, owner: this.userId, - } as Selector; + } as Filter; const options = {fields: {_id: 1, price: 1, datetime: 1}}; const minHeap = new PairingHeap(increasing); @@ -158,48 +159,53 @@ export function setupConsultationsStatsPublication( // Until then, we don't want to send a lot of `changed` messages—hence // tracking the `initializing` state. let initializing = true; - const handle = Consultations.find(selector, options).observeChanges({ - added: (_id, {price, datetime}) => { - count += 1; - if (price) total += price; - const minRef = minHeap.push(datetime); - const maxRef = maxHeap.push(datetime); - refs.set(_id, [price, minRef, maxRef]); - - if (!initializing) { - this.changed(collectionName, key, state()); - } - }, - - changed: (_id, fields) => { - const [oldPrice, minRef, maxRef] = refs.get(_id); - let newPrice: number = oldPrice; - if (Object.prototype.hasOwnProperty.call(fields, 'price')) { - newPrice = fields.price!; - if (oldPrice) total -= oldPrice; - if (newPrice) total += newPrice; - refs.set(_id, [newPrice, minRef, maxRef]); - } - - if (Object.prototype.hasOwnProperty.call(fields, 'datetime')) { - const datetime = fields.datetime; - minHeap.update(minRef, datetime); - maxHeap.update(maxRef, datetime); - } - - this.changed(collectionName, key, state()); - }, + const handle = await observeSetChanges( + Consultations, + scopedFilter, + options, + { + added: (_id, {price, datetime}) => { + count += 1; + if (price) total += price; + const minRef = minHeap.push(datetime); + const maxRef = maxHeap.push(datetime); + refs.set(_id, [price, minRef, maxRef]); + + if (!initializing) { + this.changed(collectionName, key, state()); + } + }, + + changed: (_id, fields) => { + const [oldPrice, minRef, maxRef] = refs.get(_id); + if (Object.prototype.hasOwnProperty.call(fields, 'price')) { + const newPrice = fields.price; + if (oldPrice) total -= oldPrice; + if (newPrice) total += newPrice; + refs.set(_id, [newPrice, minRef, maxRef]); + } + + if (Object.prototype.hasOwnProperty.call(fields, 'datetime')) { + const datetime = fields.datetime; + minHeap.update(minRef, datetime); + maxHeap.update(maxRef, datetime); + } - removed: (_id) => { - count -= 1; - const [price, minRef, maxRef] = refs.get(_id); - if (price) total -= price; - minHeap.delete(minRef); - maxHeap.delete(maxRef); - refs.delete(_id); - this.changed(collectionName, key, state()); + this.changed(collectionName, key, state()); + }, + + removed: (_id) => { + count -= 1; + const [price, minRef, maxRef] = refs.get(_id); + if (price) total -= price; + minHeap.delete(minRef); + maxHeap.delete(maxRef); + refs.delete(_id); + this.changed(collectionName, key, state()); + }, }, - }); + {projectionFn: ({price, datetime}) => ({price, datetime})}, + ); // Instead, we'll send one `added` message right after `observeChanges` has // returned, and mark the subscription as ready. diff --git a/imports/api/createTagCollection.ts b/imports/api/createTagCollection.ts index 4d07eccda..8959ffaf7 100644 --- a/imports/api/createTagCollection.ts +++ b/imports/api/createTagCollection.ts @@ -43,6 +43,7 @@ import type UserQuery from './query/UserQuery'; import type UserFilter from './query/UserFilter'; import type Options from './query/Options'; import type Projection from './query/Projection'; +import observeSetChanges from './query/observeSetChanges'; export const STATS_SUFFIX = '.stats'; export const FIND_CACHE_SUFFIX = '.find.cache'; @@ -190,12 +191,12 @@ const createTagCollection = < name: statsPublication, authentication: AuthenticationLoggedIn, schema: schema.tuple([schema.string()]), - handle(name) { + async handle(name) { const uid = JSON.stringify({name, owner: this.userId}); const query = { [key]: {$elemMatch: {name}}, owner: this.userId, - } as Selector

; + } as Filter

; // We only include relevant fields const options = {fields: {_id: 1, [key]: 1}}; @@ -205,22 +206,28 @@ const createTagCollection = < // `observeChanges` only returns after the initial `added` callbacks have run. // Until then, we don't want to send a lot of `changed` messages—hence // tracking the `initializing` state. - const handle = Parent.find(query, options).observeChanges({ - added: () => { - count += 1; + const handle = await observeSetChanges( + Parent, + query, + options, + { + added: () => { + count += 1; - if (!initializing) { + if (!initializing) { + this.changed(stats, uid, {count}); + } + }, + + removed: () => { + count -= 1; this.changed(stats, uid, {count}); - } - }, + }, - removed: () => { - count -= 1; - this.changed(stats, uid, {count}); + // We don't care about `changed` events. }, - - // We don't care about `changed` events. - }); + {projectionFn: (_fields) => ({})}, + ); // Instead, we'll send one `added` message right after `observeChanges` has // returned, and mark the subscription as ready. @@ -231,8 +238,8 @@ const createTagCollection = < // Stop observing the cursor when the client unsubscribes. Stopping a // subscription automatically takes care of sending the client any `removed` // messages. - this.onStop(() => { - handle.stop(); + this.onStop(async () => { + await handle.emit('stop'); }); }, }); diff --git a/imports/api/endpoint/_dev/_disableRateLimiting.ts b/imports/api/endpoint/_dev/_disableRateLimiting.ts new file mode 100644 index 000000000..c164dad5b --- /dev/null +++ b/imports/api/endpoint/_dev/_disableRateLimiting.ts @@ -0,0 +1,9 @@ +import {Meteor} from 'meteor/meteor'; +import {Accounts} from 'meteor/accounts-base'; + +import isTest from '../../../app/isTest'; + +if (Meteor.isServer && isTest()) { + // @ts-expect-error Missing from type definitions. + Accounts.removeDefaultRateLimit(); +} diff --git a/imports/api/events.ts b/imports/api/events.ts index 4e4dfdf06..48ba48d03 100644 --- a/imports/api/events.ts +++ b/imports/api/events.ts @@ -1,5 +1,7 @@ import assert from 'assert'; +import {DiffSequence} from 'meteor/diff-sequence'; + import addMilliseconds from 'date-fns/addMilliseconds'; import addMinutes from 'date-fns/addMinutes'; import isBefore from 'date-fns/isBefore'; @@ -14,9 +16,12 @@ import {DEFAULT_DURATION_IN_MINUTES} from './consultations'; import {Patients} from './collection/patients'; import {type EventDocument, events} from './collection/events'; -import findOneSync from './publication/findOneSync'; -export const event = ( +import {type Options} from './transaction/TransactionDriver'; +import observeSetChanges from './query/observeSetChanges'; +import type Filter from './query/Filter'; + +export const event = async ( _id: string, { owner, @@ -28,8 +33,9 @@ export const event = ( doneDatetime, createdAt, }: Omit, -): EventDocument => { - const patient = findOneSync(Patients, {_id: patientId}); // TODO Make reactive (maybe)? +): Promise => { + // TODO Maybe some sort of joined view? + const patient = await Patients.findOneAsync({_id: patientId}); // TODO Make reactive (maybe)? assert(patient !== undefined); const begin = datetime; const end = isDone @@ -59,17 +65,29 @@ export const event = ( }; }; -export const publishEvents = function (query, options) { - const handle = Consultations.find(query, options).observe({ - added: ({_id, ...fields}) => { - this.added(events, _id, event(_id, fields)); +export const publishEvents = async function ( + query: Filter, + options: Options, +) { + const docs = new Map(); + const handle = await observeSetChanges(Consultations, query, options, { + added: async (_id, document: Omit) => { + docs.set(_id, document); + const entry = await event(_id, document); + this.added(events, _id, entry); }, - changed: ({_id, ...fields}) => { - this.changed(events, _id, event(_id, fields)); + changed: async (_id, changes) => { + const document = docs.get(_id); + assert(document !== undefined); + DiffSequence.applyChanges(document, changes); + + const entry = await event(_id, document); + this.changed(events, _id, entry); }, - removed: ({_id}) => { + removed: (_id) => { + docs.delete(_id); this.removed(events, _id); }, }); @@ -80,8 +98,8 @@ export const publishEvents = function (query, options) { // Stop observing the cursor when the client unsubscribes. Stopping a // subscription automatically takes care of sending the client any `removed` // messages. - this.onStop(() => { - handle.stop(); + this.onStop(async () => { + await handle.emit('stop'); }); }; diff --git a/imports/api/makeCachedFindOneOpt.ts b/imports/api/makeCachedFindOneOpt.ts index bd2075988..2728b0643 100644 --- a/imports/api/makeCachedFindOneOpt.ts +++ b/imports/api/makeCachedFindOneOpt.ts @@ -1,16 +1,15 @@ import {type DependencyList, useState, useEffect} from 'react'; -import {type Meteor} from 'meteor/meteor'; import useRandom from '../ui/hooks/useRandom'; import type Publication from './publication/Publication'; import subscribe, {type SubscriptionError} from './publication/subscribe'; import type Options from './query/Options'; -import type Selector from './query/Selector'; import type Collection from './Collection'; import type Document from './Document'; - -type LiveQueryHandle = Meteor.LiveQueryHandle; +import observeSetChanges from './query/observeSetChanges'; +import type Filter from './query/Filter'; +import {type WatchHandle} from './query/watch'; /** * WARNING: Does not work properly if used multiple times with the same @@ -19,15 +18,15 @@ type LiveQueryHandle = Meteor.LiveQueryHandle; const makeCachedFindOneOpt = ( collection: Collection, - publication: Publication<[Selector, Options]>, + publication: Publication<[Filter, Options]>, ) => ( init: Partial, - selector: Selector, + filter: Filter, options: Options, deps: DependencyList, ) => { - console.debug({init, query: selector, options, deps}); + console.debug({init, query: filter, options, deps}); const [loading, setLoading] = useState(true); const [found, setFound] = useState(false); @@ -42,30 +41,36 @@ const makeCachedFindOneOpt = setFields(init); let current = init; - let queryHandle: LiveQueryHandle; - const handle = subscribe(publication, selector, options, { - onStop(e: SubscriptionError) { + let queryHandle: WatchHandle; + let stopped = false; + const handle = subscribe(publication, filter, options, { + async onStop(e: SubscriptionError) { console.debug('onStop()', {e, queryHandle}); - if (queryHandle) queryHandle.stop(); + stopped = true; + if (queryHandle !== undefined) await queryHandle.emit('stop'); else reset(); }, - onReady() { + async onReady() { console.debug('onReady()'); setLoading(false); - queryHandle = collection.find(selector, options).observeChanges({ + queryHandle = await observeSetChanges(collection, filter, options, { added(_id, upToDate) { + if (stopped) return; setFound(true); current = {...init, ...upToDate}; setFields(current); }, changed(_id, upToDate) { + if (stopped) return; current = {...current, ...upToDate}; setFields(current); }, removed(_id) { + if (stopped) return; setFound(false); }, }); + if (stopped) await queryHandle.emit('stop'); }, }); diff --git a/imports/api/makeFilteredCollection.ts b/imports/api/makeFilteredCollection.ts index 283031e42..406136bc8 100644 --- a/imports/api/makeFilteredCollection.ts +++ b/imports/api/makeFilteredCollection.ts @@ -14,6 +14,9 @@ import useSubscription from './publication/useSubscription'; import {AuthenticationLoggedIn} from './Authentication'; import {userFilter} from './query/UserFilter'; import type UserFilter from './query/UserFilter'; +import observeSetChanges from './query/observeSetChanges'; +import type Filter from './query/Filter'; +import {publishCursorObserver} from './publication/publishCursors'; const makeFilteredCollection = < S extends schema.ZodTypeAny, @@ -32,15 +35,15 @@ const makeFilteredCollection = < userFilter(tSchema).nullable(), options(tSchema).nullable(), ]), - handle( + async handle( publicationFilter: UserFilter> | null, publicationOptions: Options> | null, ) { - const selector = { + const scopedFilter = { ...filterSelector, ...publicationFilter, owner: this.userId, - } as Selector>; + } as Filter>; const options = { ...filterOptions, @@ -49,22 +52,15 @@ const makeFilteredCollection = < limit: 0, }; - const handle = collection.find(selector, options).observeChanges({ - added: (_id, fields) => { - this.added(name, _id, fields); - }, + const handle = await observeSetChanges( + collection, + scopedFilter, + options, + publishCursorObserver(this, name), + ); - changed: (_id, fields) => { - this.changed(name, _id, fields); - }, - - removed: (_id) => { - this.removed(name, _id); - }, - }); - - this.onStop(() => { - handle.stop(); + this.onStop(async () => { + await handle.emit('stop'); }); this.ready(); }, diff --git a/imports/api/makeObservedQueryHook.ts b/imports/api/makeObservedQueryHook.ts index dbb08f539..4d1f3f254 100644 --- a/imports/api/makeObservedQueryHook.ts +++ b/imports/api/makeObservedQueryHook.ts @@ -1,6 +1,5 @@ -import {type DependencyList, useEffect, useRef} from 'react'; +import {type DependencyList, useEffect, useRef, useState} from 'react'; -import useForceUpdate from '../ui/hooks/useForceUpdate'; import useChanged from '../ui/hooks/useChanged'; import type ObservedQueryCacheCollection from './ObservedQueryCacheCollection'; @@ -19,42 +18,30 @@ const makeObservedQueryHook = publication: Publication<[string, UserQuery, ObserveOptions | null]>, ): GenericQueryHook => (query: UserQuery, deps: DependencyList) => { - const loading = useRef(true); - const results = useRef([]); - const dirty = useRef(false); + const [loading, setLoading] = useState(true); + const [results, setResults] = useState([]); + const [dirty, setDirty] = useState(false); const handleRef = useRef(null); - const forceUpdate = useForceUpdate(); const effectWillTrigger = useChanged(deps); - if (effectWillTrigger) { - // This is to make sure we return the correct values on first - // render. - // TODO Find a better way to do this. It may cause problems in - // future concurrent mode. - dirty.current = false; - loading.current = true; - } - useEffect(() => { - dirty.current = false; - loading.current = true; + setDirty(false); + setLoading(true); const timestamp = Date.now(); const key = JSON.stringify({timestamp, query}); const handle = subscribe(publication, key, query, null, { onStop() { if (handleRef.current === handle) { - dirty.current = true; - loading.current = false; - forceUpdate(); + setDirty(true); + setLoading(false); } }, onReady() { if (handleRef.current === handle) { - results.current = findOneSync(Collection, {key})?.results ?? []; - loading.current = false; - forceUpdate(); + setResults(findOneSync(Collection, {key})?.results ?? []); + setLoading(false); } }, }); @@ -66,9 +53,9 @@ const makeObservedQueryHook = }, deps); return { - loading: loading.current, - results: results.current, - dirty: dirty.current, + loading: effectWillTrigger || loading, + results, + dirty: !effectWillTrigger && dirty, }; }; diff --git a/imports/api/makeObservedQueryPublication.ts b/imports/api/makeObservedQueryPublication.ts index 2c2ac97a6..5f26cfeaf 100644 --- a/imports/api/makeObservedQueryPublication.ts +++ b/imports/api/makeObservedQueryPublication.ts @@ -1,15 +1,21 @@ +import {DiffSequence} from 'meteor/diff-sequence'; + import schema from '../lib/schema'; import type Collection from './Collection'; import type Document from './Document'; +import type Filter from './query/Filter'; import type ObserveChangesCallbacks from './ObserveChangesCallbacks'; import queryToSelectorOptionsPair from './query/queryToSelectorOptionsPair'; import {userQuery} from './query/UserQuery'; import type UserQuery from './query/UserQuery'; +import watch from './query/watch'; +import {type Context} from './publication/Context'; const observeOptions = schema .object({ - added: schema.boolean().optional(), + addedBefore: schema.boolean().optional(), + movedBefore: schema.boolean().optional(), removed: schema.boolean().optional(), changed: schema.boolean().optional(), }) @@ -28,58 +34,83 @@ const makeObservedQueryPublication = ( QueriedCollection: Collection, observedQueryCacheCollectionName: string, ) => - function (key: string, query: UserQuery, observe: ObserveOptions | null) { + async function ( + this: Context, + key: string, + query: UserQuery, + observe: ObserveOptions | null, + ) { let [selector, options] = queryToSelectorOptionsPair(query); selector = { ...selector, owner: this.userId, }; + const callbacks: ObserveOptions = { - added: true, + addedBefore: true, + movedBefore: true, removed: true, ...observe, }; + const uid = JSON.stringify({ key, selector, options, observe, }); - const results: T[] = []; - let initializing = true; const stop = () => { this.stop(); }; - const observers: ObserveChangesCallbacks = { - added(_id, fields) { - if (initializing) results.push({_id, ...fields} as unknown as T); - else if (callbacks.added) stop(); - }, - }; + // NOTE We diff ids only if we do not care about change events. + const diffOptions = callbacks.changed + ? undefined + : { + projectionFn: (_fields: T) => ({}), + }; + + const observer: ObserveChangesCallbacks = {}; + + if (callbacks.addedBefore) observer.addedBefore = stop; + if (callbacks.movedBefore) observer.movedBefore = stop; + if (callbacks.removed) observer.removed = stop; + if (callbacks.changed) observer.changed = stop; - if (callbacks.removed) observers.removed = stop; - if (callbacks.changed) observers.changed = stop; + const handle = await watch( + QueriedCollection, + selector as Filter, + options, + ); - const handle = QueriedCollection.find(selector, options).observeChanges( - observers, + handle.once('change').then( + async (init) => { + handle.on('change', async (next) => { + DiffSequence.diffQueryOrderedChanges( + init, + next, + observer, + diffOptions, + ); + }); + + this.added(observedQueryCacheCollectionName, uid, { + key, + results: init, + }); + this.ready(); + }, + (error: Error) => { + this.error(error); + }, ); - // Instead, we'll send one `added` message right after `observeChanges` has - // returned, and mark the subscription as ready. - initializing = false; - this.added(observedQueryCacheCollectionName, uid, { - key, - results, - }); - this.ready(); + await handle.emit('start'); - // Stop observing the cursor when the client unsubscribes. Stopping a - // subscription automatically takes care of sending the client any `removed` - // messages. - this.onStop(() => { - handle.stop(); + // NOTE: Stop observing the cursor when the client unsubscribes. + this.onStop(async () => { + await handle.emit('stop'); }); }; diff --git a/imports/api/publication/consultations/stats.ts b/imports/api/publication/consultations/stats.ts index 3c521de0a..8d0b56609 100644 --- a/imports/api/publication/consultations/stats.ts +++ b/imports/api/publication/consultations/stats.ts @@ -14,10 +14,10 @@ export default define({ name: stats, authentication: AuthenticationLoggedIn, schema: schema.tuple([userFilter(consultationDocument)]), - handle(filter: UserFilter) { + async handle(filter: UserFilter) { const collection = stats; - const handle = setupConsultationsStatsPublication.call( + const handle = await setupConsultationsStatsPublication.call( this, collection, filter, @@ -27,8 +27,8 @@ export default define({ // Stop observing the cursor when the client unsubscribes. Stopping a // subscription automatically takes care of sending the client any `removed` // messages. - this.onStop(() => { - handle.stop(); + this.onStop(async () => { + await handle.emit('stop'); }); }, }); diff --git a/imports/api/publication/define.ts b/imports/api/publication/define.ts index 90633024f..92f6f7bb7 100644 --- a/imports/api/publication/define.ts +++ b/imports/api/publication/define.ts @@ -2,8 +2,8 @@ import assert from 'assert'; import {Meteor} from 'meteor/meteor'; -import {map} from '@iterable-iterator/map'; -import {sum} from '@iterable-iterator/reduce'; +import {filter} from '@iterable-iterator/filter'; +import {next} from '@iterable-iterator/next'; import authorized from '../authorized'; import {type Authentication} from '../Authentication'; @@ -12,11 +12,11 @@ import type ArgsSchema from '../ArgsSchema'; import type Params from './Params'; import type Publication from './Publication'; -import PublicationError from './PublicationError'; +import type Cursor from './Cursor'; +import publishCursors from './publishCursors'; -// TODO early branch out -const exactlyOne = (array: any[]) => - sum(map((x: any) => (x ? 1 : 0), array)) === 1; +import PublicationError from './PublicationError'; +import {type Context} from './Context'; const define = < S extends ArgsSchema, @@ -32,40 +32,78 @@ const define = < }: Params): Publication => { if (Meteor.isServer) { // @ts-expect-error Ignore this for now. - const fns = [rest.cursor, rest.cursors, rest.handle]; - assert(exactlyOne(fns)); - for (const fn of fns) { - if (fn) { - Meteor.publish(name, function (...args) { - if (!authorized(authentication, this)) { - this.ready(); - return; - } - - let parsedArgs: A; - - try { - schema.parse(args); - parsedArgs = args as A; // TODO Use parsed value once it does not reorder object keys. - } catch (error: unknown) { - console.debug({ - publication: name, - args: JSON.stringify(args), - error, - }); - throw new PublicationError( - 'schema validation of publication args failed', - ); - } - - return Reflect.apply(fn, this, parsedArgs); - }); - break; + const {cursor, cursors, handle} = rest; + const defined = filter( + (x: unknown) => x !== undefined, + [cursor, cursors, handle], + ); + const callback = next(defined); + assert(next(defined, null) === null); + + const postProcess = _getPostProcess({cursor, cursors, handle}, callback); + + Meteor.publish(name, async function (...args) { + if (!authorized(authentication, this)) { + this.ready(); + return; } - } + + const parsedArgs = _parse(name, schema, args); + + const result = await Reflect.apply(callback, this, parsedArgs); + return postProcess(this, result); + }); } return {name}; }; +const _getPostProcess = ( + {cursor, cursors, handle}: Record, + callback: T, +) => { + switch (callback) { + case cursor: { + return postProcessCursor; + } + + case cursors: { + return postProcessCursors; + } + + default: { + assert(callback === handle); + return postProcessHandle; + } + } +}; + +const _parse = = InferArgs>( + name: string, + schema: S, + args: unknown[], +): A => { + try { + schema.parse(args); + return args as A; // TODO Use parsed value once it does not reorder object keys. + } catch (error: unknown) { + console.debug({ + publication: name, + args: JSON.stringify(args), + error, + }); + throw new PublicationError('schema validation of publication args failed'); + } +}; + +const postProcessCursor = async ( + context: Context, + cursor: Cursor, +) => publishCursors(context, [cursor]); +const postProcessCursors = async ( + context: Context, + cursors: Array>, +) => publishCursors(context, cursors); +const postProcessHandle = (_context: Context, result: any) => result; + export default define; diff --git a/imports/api/publication/events/intersects.ts b/imports/api/publication/events/intersects.ts index 697af0ccc..e4dc5edfd 100644 --- a/imports/api/publication/events/intersects.ts +++ b/imports/api/publication/events/intersects.ts @@ -4,13 +4,14 @@ import schema from '../../../lib/schema'; import {AuthenticationLoggedIn} from '../../Authentication'; import {intersectsInterval, publishEvents} from '../../events'; import define from '../define'; +import PublicationError from '../PublicationError'; export default define({ name: 'events.intersects', authentication: AuthenticationLoggedIn, schema: schema.tuple([schema.date(), schema.date()]), - handle(begin, end) { - if (isAfter(begin, end)) throw new Error('begin is after end'); + async handle(begin, end) { + if (isAfter(begin, end)) throw new PublicationError('begin is after end'); const query = { ...intersectsInterval(begin, end), @@ -32,6 +33,6 @@ export default define({ }, }; - publishEvents.call(this, query, options); + return publishEvents.call(this, query, options); }, }); diff --git a/imports/api/publication/events/interval.ts b/imports/api/publication/events/interval.ts index cd6803323..dc3e9884a 100644 --- a/imports/api/publication/events/interval.ts +++ b/imports/api/publication/events/interval.ts @@ -7,7 +7,7 @@ export default define({ name: 'events.interval', authentication: AuthenticationLoggedIn, schema: schema.tuple([schema.date(), schema.date()]), - handle(begin, end) { + async handle(begin, end) { const query = { ...beginsInInterval(begin, end), owner: this.userId, @@ -28,6 +28,6 @@ export default define({ }, }; - publishEvents.call(this, query, options); + return publishEvents.call(this, query, options); }, }); diff --git a/imports/api/publication/patient/noShows.ts b/imports/api/publication/patient/noShows.ts index b6547d74f..a50a16ad7 100644 --- a/imports/api/publication/patient/noShows.ts +++ b/imports/api/publication/patient/noShows.ts @@ -7,16 +7,17 @@ import {noShows, type State} from '../../collection/noShows'; import define from '../define'; import {AuthenticationLoggedIn} from '../../Authentication'; import schema from '../../../lib/schema'; +import observeSetChanges from '../../query/observeSetChanges'; export default define({ name: 'patient.noShows', authentication: AuthenticationLoggedIn, schema: schema.tuple([schema.string()]), - handle(patientId) { + async handle(patientId) { const Collection = Appointments; const collection = noShows; const key = patientId; - const selector = { + const filter = { owner: this.userId, patientId, isDone: false, @@ -29,23 +30,29 @@ export default define({ const state = (): State => ({count}); let initializing = true; - const handle = Collection.find(selector, options).observeChanges({ - added: (_id, _fields) => { - count += 1; - if (!initializing) { + const handle = await observeSetChanges( + Collection, + filter, + options, + { + added: (_id, _fields) => { + count += 1; + if (!initializing) { + this.changed(collection, key, state()); + } + }, + removed: (_id) => { + count -= 1; this.changed(collection, key, state()); - } + }, }, - removed: (_id) => { - count -= 1; - this.changed(collection, key, state()); - }, - }); + {projectionFn: (_fields) => ({})}, + ); initializing = false; this.added(collection, key, state()); - this.onStop(() => { - handle.stop(); + this.onStop(async () => { + await handle.emit('stop'); }); this.ready(); }, diff --git a/imports/api/publication/publishCursors.tests.ts b/imports/api/publication/publishCursors.tests.ts new file mode 100644 index 000000000..bbf27c7a6 --- /dev/null +++ b/imports/api/publication/publishCursors.tests.ts @@ -0,0 +1,245 @@ +import {chain} from '@iterable-iterator/chain'; +import {filter} from '@iterable-iterator/filter'; +import {map} from '@iterable-iterator/map'; +import {list} from '@iterable-iterator/list'; + +import {assert} from 'chai'; + +import {randomUserId, server} from '../../_test/fixtures'; +import {newPatient} from '../_dev/populate/patients'; +import {Patients} from '../collection/patients'; + +import type Document from '../Document'; +import {newConsultation} from '../_dev/populate/consultations'; +import {Consultations} from '../collection/consultations'; +import {Appointments} from '../collection/appointments'; +import {Attachments} from '../collection/attachments'; + +import publishCursors from './publishCursors'; +import {type Context} from './Context'; + +type ReadyCall = ['ready']; +type StopCall = ['stop']; +type OnStopCall = ['onStop', () => Promise | void]; +type UnblockCall = ['unblock']; +type ErrorCall = ['error', Error]; +type AddedCall = ['added', string, string, Document]; +type ChangedCall = ['changed', string, string, Document]; +type RemovedCall = ['removed', string, string]; + +type Call = + | ReadyCall + | StopCall + | OnStopCall + | UnblockCall + | ErrorCall + | AddedCall + | ChangedCall + | RemovedCall; + +type ContextState = { + calls: { + push: (call: Call) => void; + all: () => Call[]; + ready: () => ReadyCall[]; + stop: () => StopCall[]; + onStop: () => OnStopCall[]; + unblock: () => UnblockCall[]; + error: () => ErrorCall[]; + added: () => AddedCall[]; + changed: () => ChangedCall[]; + removed: () => RemovedCall[]; + }; +}; + +const makeMockedContextState = (): ContextState => { + const _calls: Call[] = []; + return { + calls: { + all: () => list(_calls), + ready: () => list(filter(([method]) => method === 'ready', _calls)), + stop: () => list(filter(([method]) => method === 'stop', _calls)), + onStop: () => list(filter(([method]) => method === 'onStop', _calls)), + unblock: () => list(filter(([method]) => method === 'unblock', _calls)), + error: () => list(filter(([method]) => method === 'error', _calls)), + added: () => list(filter(([method]) => method === 'added', _calls)), + changed: () => list(filter(([method]) => method === 'changed', _calls)), + removed: () => list(filter(([method]) => method === 'removed', _calls)), + push(call: Call) { + _calls.push(call); + }, + }, + }; +}; + +const makeMockedContext = ( + state: ContextState, + userId: string | null, +): Context => { + return { + connection: { + id: '', + clientAddress: '', + httpHeaders: {}, + // eslint-disable-next-line @typescript-eslint/no-empty-function + close() {}, + // eslint-disable-next-line @typescript-eslint/no-empty-function + onClose() {}, + }, + userId, + error(error: Error) { + state.calls.push(['error', error]); + }, + ready() { + state.calls.push(['ready']); + }, + stop() { + state.calls.push(['stop']); + }, + onStop(callback: () => Promise | void) { + state.calls.push(['onStop', callback]); + }, + unblock() { + state.calls.push(['unblock']); + }, + added(collection: string, id: string, fields: Document) { + state.calls.push(['added', collection, id, fields]); + }, + changed(collection: string, id: string, fields: Document) { + state.calls.push(['changed', collection, id, fields]); + }, + removed(collection: string, id: string) { + state.calls.push(['removed', collection, id]); + }, + }; +}; + +server(__filename, () => { + it('should handle one cursor', async () => { + const userId = randomUserId(); + await newPatient({userId}); + await newPatient({userId}); + await newPatient({userId}); + const filter = {}; + const cursor = Patients.find(filter); + const patients = await Patients.find(filter).fetchAsync(); + + const state = makeMockedContextState(); + const context = makeMockedContext(state, userId); + await publishCursors(context, [cursor]); + + const {calls} = state; + assert.lengthOf(calls.onStop(), 1); + assert.lengthOf(calls.ready(), 1); + + assert.deepEqual(calls.error(), []); + assert.deepEqual(calls.stop(), []); + + assert.deepEqual(calls.unblock(), []); + + assert.deepEqual(calls.removed(), []); + assert.deepEqual(calls.changed(), []); + assert.sameDeepMembers( + calls.added(), + list( + chain( + map(({_id, ...rest}) => ['added', 'patients', _id, rest], patients), + ), + ), + ); + }); + + it('should handle two cursors', async () => { + const userId = randomUserId(); + + const patientId = await newPatient({userId}); + await newPatient({userId}); + await newPatient({userId}); + const filter = {}; + + const patientsCursor = Patients.find(filter); + const patients = await Patients.find(filter).fetchAsync(); + + await newConsultation({userId}, {patientId}); + await newConsultation({userId}, {patientId}); + + const consultationsCursor = Consultations.find(filter); + const consultations = await Consultations.find(filter).fetchAsync(); + + const state = makeMockedContextState(); + const context = makeMockedContext(state, userId); + await publishCursors(context, [patientsCursor, consultationsCursor]); + + const {calls} = state; + assert.lengthOf(calls.onStop(), 2); + assert.lengthOf(calls.ready(), 1); + + assert.deepEqual(calls.error(), []); + assert.deepEqual(calls.stop(), []); + + assert.deepEqual(calls.unblock(), []); + + assert.deepEqual(calls.removed(), []); + assert.deepEqual(calls.changed(), []); + assert.sameDeepMembers( + calls.added(), + list( + chain( + map(({_id, ...rest}) => ['added', 'patients', _id, rest], patients), + map( + ({_id, ...rest}) => ['added', 'consultations', _id, rest], + consultations, + ), + ), + ), + ); + }); + + it('should error if cursors cannot be merged', async () => { + const filter = {}; + const a = Consultations.find(filter); + const b = Appointments.find(filter); + + const state = makeMockedContextState(); + const context = makeMockedContext(state, null); + await publishCursors(context, [a, b]); + + const {calls} = state; + assert.lengthOf(calls.error(), 1); + + assert.deepEqual(calls.onStop(), []); + assert.deepEqual(calls.ready(), []); + + assert.deepEqual(calls.stop(), []); + + assert.deepEqual(calls.unblock(), []); + + assert.deepEqual(calls.removed(), []); + assert.deepEqual(calls.changed(), []); + assert.deepEqual(calls.added(), []); + }); + + it('should not error if cursors can be merged', async () => { + const filter = {}; + const a = Patients.find(filter); + const b = Appointments.find(filter); + const c = Attachments.find(filter); + + const state = makeMockedContextState(); + const context = makeMockedContext(state, null); + await publishCursors(context, [a, b, c]); + + const {calls} = state; + assert.lengthOf(calls.onStop(), 3); + assert.lengthOf(calls.ready(), 1); + + assert.deepEqual(calls.error(), []); + assert.deepEqual(calls.stop(), []); + + assert.deepEqual(calls.unblock(), []); + + assert.deepEqual(calls.removed(), []); + assert.deepEqual(calls.changed(), []); + assert.deepEqual(calls.added(), []); + }); +}); diff --git a/imports/api/publication/publishCursors.ts b/imports/api/publication/publishCursors.ts new file mode 100644 index 000000000..ad8625591 --- /dev/null +++ b/imports/api/publication/publishCursors.ts @@ -0,0 +1,97 @@ +import observeSetChanges from '../query/observeSetChanges'; +import type Filter from '../query/Filter'; +import type Document from '../Document'; + +import duplicates from '../../lib/iterable-iterator/duplicates'; +import unique from '../../lib/iterable-iterator/unique'; + +import {getCollection} from '../collection/registry'; + +import type ObserveSetChangesCallbacks from '../ObserveSetChangesCallbacks'; + +import {type Context} from './Context'; +import type Cursor from './Cursor'; + +const _assertCursorsCanBeMerged = ( + cursors: Array>, +): void => { + const collections = cursors.map((cursor) => cursor._getCollectionName()); + const duplicated = Array.from(unique(duplicates(collections))); + if (duplicated.length > 0) { + throw new Error( + `Publish function returned multiple cursors for collections in ${JSON.stringify( + duplicated, + )}`, + ); + } +}; + +const publishCursors = async ( + subscription: Context, + cursors: Array>, +): Promise => { + try { + _assertCursorsCanBeMerged(cursors); + } catch (error: unknown) { + subscription.error(error as Error); + return; + } + + return _publishCursors(subscription, cursors); +}; + +const _publishCursors = async ( + subscription: Context, + cursors: Array>, +): Promise => { + try { + const pipes = await Promise.all( + cursors.map(async (cursor) => _pipe(subscription, cursor)), + ); + + for (const pipe of pipes) { + subscription.onStop(async () => pipe.emit('stop')); + } + + subscription.ready(); + } catch (error: unknown) { + subscription.error(error as Error); + } +}; + +const _pipe = async ( + subscription: Context, + cursor: Cursor, +) => { + const collection = cursor._getCollectionName(); + const QueriedCollection = getCollection(collection); + const { + _cursorDescription: {selector, options}, + } = cursor; + + const filter = selector as Filter; + + return observeSetChanges( + QueriedCollection, + filter, + options, + publishCursorObserver(subscription, collection), + ); +}; + +export const publishCursorObserver = ( + subscription: Context, + collection: string, +): ObserveSetChangesCallbacks => ({ + added(id, fields) { + subscription.added(collection, id, fields); + }, + changed(id, fields) { + subscription.changed(collection, id, fields); + }, + removed(id) { + subscription.removed(collection, id); + }, +}); + +export default publishCursors; diff --git a/imports/api/publication/stats/frequencyBySex.ts b/imports/api/publication/stats/frequencyBySex.ts index c33204972..eeb82d193 100644 --- a/imports/api/publication/stats/frequencyBySex.ts +++ b/imports/api/publication/stats/frequencyBySex.ts @@ -1,3 +1,5 @@ +import assert from 'assert'; + import schema from '../../../lib/schema'; import {AuthenticationLoggedIn} from '../../Authentication'; import { @@ -7,10 +9,11 @@ import { } from '../../collection/consultations'; import {Patients} from '../../collection/patients'; import {countCollection, type PollResult} from '../../collection/stats'; -import type Selector from '../../query/Selector'; import define from '../define'; import {userFilter} from '../../query/UserFilter'; import type UserFilter from '../../query/UserFilter'; +import observeSetChanges from '../../query/observeSetChanges'; +import type Filter from '../../query/Filter'; export const frequencySexKey = (query) => `frequencySex-${JSON.stringify(query ?? {})}`; @@ -24,26 +27,33 @@ export type GenderCount = { undefined?: number; }; +type Consultation = string; +type Patient = { + consultations: Set; + sex: keyof GenderCount; + removed: boolean; +}; + export default define({ name: frequencySexPublication, authentication: AuthenticationLoggedIn, schema: schema.tuple([userFilter(consultationDocument).nullable()]), - handle(filter: UserFilter | null) { + async handle(filter: UserFilter | null) { const collection = countCollection; const key = frequencySexKey(filter); const selector = { ...filter, isDone: true, owner: this.userId, - } as Selector; + } as Filter; const options = { fields: { patientId: 1, }, }; let total = 0; - const refs = new Map(); - const pRefs = new Map(); + const cRefs = new Map(); + const pRefs = new Map(); const count: [GenderCount, ...GenderCount[]] = [{}]; const state = (): PollResult => ({ @@ -51,30 +61,29 @@ export default define({ count, }); - const inc = (patientId: string | undefined) => { - if (patientId === undefined || !pRefs.has(patientId)) - throw new Error(`inc: patientId ${patientId} does not exist`); - const patient = pRefs.get(patientId)!; - count[patient.freq]![patient.sex ?? 'undefined'] -= 1; - patient.freq += 1; - if (count[patient.freq] === undefined) count[patient.freq] = {}; - if (count[patient.freq]![patient.sex ?? 'undefined'] === undefined) - count[patient.freq]![patient.sex ?? 'undefined'] = 0; - // eslint-disable-next-line @typescript-eslint/restrict-plus-operands - count[patient.freq]![patient.sex ?? 'undefined'] += 1; + const _erase = (freq: number, sex: keyof GenderCount) => { + const {[sex]: current, ...rest} = count[freq]!; + assert(current !== undefined); + count[freq] = current === 1 ? rest : {[sex]: current - 1, ...rest}; }; - const dec = (patientId: string | undefined) => { - if (patientId === undefined || !pRefs.has(patientId)) - throw new Error(`dec: patientId ${patientId} does not exist`); - const patient = pRefs.get(patientId)!; - count[patient.freq]![patient.sex ?? 'undefined'] -= 1; - patient.freq -= 1; - if (count[patient.freq] === undefined) count[patient.freq] = {}; - if (count[patient.freq]![patient.sex ?? 'undefined'] === undefined) - count[patient.freq]![patient.sex ?? 'undefined'] = 0; + const _record = (freq: number, sex: string) => { + if (count[freq] === undefined) count[freq] = {}; + if (count[freq]![sex] === undefined) count[freq]![sex] = 0; // eslint-disable-next-line @typescript-eslint/restrict-plus-operands - count[patient.freq]![patient.sex ?? 'undefined'] += 1; + count[freq]![sex] += 1; + }; + + const inc = (patient: Patient) => { + total += 1; + _erase(patient.consultations.size, patient.sex); + _record(patient.consultations.size + 1, patient.sex); + }; + + const dec = (patient: Patient) => { + total -= 1; + _erase(patient.consultations.size, patient.sex); + _record(patient.consultations.size - 1, patient.sex); }; let initializing = true; @@ -84,66 +93,113 @@ export default define({ } }; - const pHandle = Patients.find( + const _ensurePatient = (patientId: string) => { + const existing = pRefs.get(patientId); + if (existing !== undefined) return existing; + + const removed: Patient = { + consultations: new Set(), + sex: 'undefined', + removed: true, + }; + pRefs.set(patientId, removed); + return removed; + }; + + const addConsultation = (patientId: string, consultationId: string) => { + const patient = _ensurePatient(patientId); + if (!patient.removed) inc(patient); + patient.consultations.add(consultationId); + cRefs.set(consultationId, patientId); + }; + + const removeConsultation = (patientId: string, consultationId: string) => { + const patient = pRefs.get(patientId); + assert(patient !== undefined); + if (!patient.removed) dec(patient); + patient.consultations.delete(consultationId); + cRefs.delete(consultationId); + }; + + const pHandle = await observeSetChanges( + Patients, {owner: this.userId}, {fields: {sex: 1}}, - ).observeChanges({ - added(_id, {sex}) { - const sexKey = `${sex}`; - pRefs.set(_id, {freq: 0, sex: sexKey}); - if (count[0][sexKey] === undefined) count[0][sexKey] = 0; - // eslint-disable-next-line @typescript-eslint/restrict-plus-operands - count[0][sexKey] += 1; - commit(); - }, - changed(_id, {sex}) { - const {freq, sex: prev} = pRefs.get(_id)!; - const prevKey = `${prev}`; - count[freq]![prevKey] -= 1; - const sexKey = `${sex}`; - if (count[freq]![sexKey] === undefined) count[freq]![sexKey] = 0; - // eslint-disable-next-line @typescript-eslint/restrict-plus-operands - count[freq]![sexKey] += 1; - pRefs.set(_id, {freq, sex: sexKey}); - commit(); + { + added(_id, {sex}) { + const sexKey: keyof GenderCount = `${sex}`; + const previous = pRefs.get(_id); + assert(previous === undefined || previous.removed); + const consultations = previous?.consultations ?? new Set(); + pRefs.set(_id, {consultations, sex: sexKey, removed: false}); + + _record(consultations.size, sexKey); + + total += consultations.size; + commit(); + }, + changed(_id, {sex}) { + const {consultations, sex: prevKey, removed} = pRefs.get(_id)!; + assert(!removed); + const freq = consultations.size; + _erase(freq, prevKey); + const sexKey: keyof GenderCount = `${sex}`; + _record(freq, sexKey); + pRefs.set(_id, {consultations, sex: sexKey, removed: false}); + commit(); + }, + removed(_id) { + const patient = pRefs.get(_id); + assert(patient !== undefined); + assert(!patient.removed); + const sexKey = patient.sex; + if (patient.consultations.size === 0) { + _erase(0, sexKey); + pRefs.delete(_id); + } else { + pRefs.set(_id, {...patient, removed: true}); + total -= patient.consultations.size; + _erase(patient.consultations.size, patient.sex); + } + + commit(); + }, }, - removed(_id) { - pRefs.delete(_id); - // everything should be commited by the consultations observer + { + projectionFn: ({sex}) => ({sex}), }, - }); + ); - const cHandle = Consultations.find(selector, options).observeChanges({ - added(_id, {patientId}) { - if (patientId === undefined) - throw new Error( - `added: consultation ${_id} is not linked to a patient.`, - ); - total += 1; - inc(patientId); - refs.set(_id, patientId); - commit(); - }, + const cHandle = await observeSetChanges( + Consultations, + selector, + options, + { + added(_id, {patientId}) { + assert(patientId !== undefined); + addConsultation(patientId, _id); + commit(); + }, - // changed: ... // TODO We assume a consultation does not change - // patientId. Handle that. + // changed: ... // TODO We assume a consultation does not change + // patientId. Handle that. - removed(_id) { - total -= 1; - const patientId = refs.get(_id)!; - dec(patientId); - refs.delete(_id); - commit(); + removed(_id) { + const patientId = cRefs.get(_id); + assert(patientId !== undefined); + removeConsultation(patientId, _id); + commit(); + }, }, - }); + {projectionFn: ({patientId}) => ({patientId})}, + ); initializing = false; this.added(collection, key, state()); this.ready(); - this.onStop(() => { - cHandle.stop(); - pHandle.stop(); + this.onStop(async () => { + await Promise.all([cHandle.emit('stop'), pHandle.emit('stop')]); }); }, }); diff --git a/imports/api/publication/useSubscription.ts b/imports/api/publication/useSubscription.ts index 2fee139a2..e6e5471bb 100644 --- a/imports/api/publication/useSubscription.ts +++ b/imports/api/publication/useSubscription.ts @@ -1,6 +1,5 @@ import {Meteor} from 'meteor/meteor'; -import {Tracker} from 'meteor/tracker'; -import {useState, useEffect} from 'react'; +import {useState, useEffect, useRef} from 'react'; import useChanged from '../../ui/hooks/useChanged'; @@ -8,26 +7,41 @@ import type Args from '../Args'; import subscribe from './subscribe'; import type Publication from './Publication'; +import type SubscriptionHandle from './SubscriptionHandle'; const useSubscriptionClient = ( publication?: Publication | null, ...args: A ): (() => boolean) => { const [loading, setLoading] = useState(true); + const handleRef = useRef(null); - const deps = [publication, JSON.stringify(args)]; + const deps = [setLoading, publication, JSON.stringify(args)]; useEffect(() => { - const computation = Tracker.nonreactive(() => - Tracker.autorun(() => { - const ready = !publication || subscribe(publication, ...args).ready(); - setLoading(!ready); - }), - ); - - // Stop the computation on when publication changes or unmount. + if (!publication) return undefined; + const setNotLoading = () => { + if (handleRef.current === handle) setLoading(false); + }; + + const callbacks = { + onReady: setNotLoading, + onStop: setNotLoading, + onError: setNotLoading, + }; + + const handle = subscribe(publication, ...args, callbacks); + handleRef.current = handle; + + // NOTE `setLoading(true)` is called: + // - on first execution, + // - on subsequent executions, if the subscription is not ready yet + // (e.g. double-render in strict mode in development, concurrent mode) + // - when restarting a stopped or errored subscription + setLoading(!handle.ready()); + return () => { - computation.stop(); + handle.stop(); }; }, deps); diff --git a/imports/api/query/observeSequenceChanges.ts b/imports/api/query/observeSequenceChanges.ts new file mode 100644 index 000000000..d9f2ac78f --- /dev/null +++ b/imports/api/query/observeSequenceChanges.ts @@ -0,0 +1,42 @@ +import {type DiffOptions, DiffSequence} from 'meteor/diff-sequence'; + +import type Collection from '../Collection'; +import type Document from '../Document'; + +import type ObserveSequenceChangesCallbacks from '../ObserveSequenceChangesCallbacks'; +import {type Options} from '../transaction/TransactionDriver'; + +import type Filter from './Filter'; +import watch from './watch'; + +const _makeOnChange = ( + observer: ObserveSequenceChangesCallbacks, + diffOptions: DiffOptions | undefined, +) => { + let previous: T[] = []; + + return (next: T[]) => { + DiffSequence.diffQueryOrderedChanges( + previous, + next, + observer, + diffOptions, + ); + previous = next; + }; +}; + +const observeSequenceChanges = async ( + collection: Collection, + filter: Filter, + options: Options, + observer: ObserveSequenceChangesCallbacks, + diffOptions?: DiffOptions, +) => { + const handle = await watch(collection, filter, options); + handle.on('change', _makeOnChange(observer, diffOptions)); + await handle.emit('start'); + return handle; +}; + +export default observeSequenceChanges; diff --git a/imports/api/query/observeSetChanges.ts b/imports/api/query/observeSetChanges.ts new file mode 100644 index 000000000..7414945dd --- /dev/null +++ b/imports/api/query/observeSetChanges.ts @@ -0,0 +1,46 @@ +import {type DiffOptions, DiffSequence} from 'meteor/diff-sequence'; + +import type Collection from '../Collection'; +import type Document from '../Document'; + +import type ObserveSetChangesCallbacks from '../ObserveSetChangesCallbacks'; +import {type Options} from '../transaction/TransactionDriver'; + +import type Filter from './Filter'; +import watch from './watch'; + +const _toSet = (items: T[]): Map => + new Map(items.map((item) => [item._id, item])); + +const _makeOnChange = ( + observer: ObserveSetChangesCallbacks, + diffOptions: DiffOptions | undefined, +) => { + let previous = _toSet([]); + + return (items: T[]) => { + const next = _toSet(items); + DiffSequence.diffQueryUnorderedChanges( + previous, + next, + observer, + diffOptions, + ); + previous = next; + }; +}; + +const observeSetChanges = async ( + collection: Collection, + filter: Filter, + options: Options, + observer: ObserveSetChangesCallbacks, + diffOptions?: DiffOptions, +) => { + const handle = await watch(collection, filter, options); + handle.on('change', _makeOnChange(observer, diffOptions)); + await handle.emit('start'); + return handle; +}; + +export default observeSetChanges; diff --git a/imports/api/query/watch.ts b/imports/api/query/watch.ts new file mode 100644 index 000000000..217b981c0 --- /dev/null +++ b/imports/api/query/watch.ts @@ -0,0 +1,245 @@ +import assert from 'assert'; + +import { + type ClientSessionOptions, + type TransactionOptions, + type ChangeStreamOptions, + type Timestamp, +} from 'mongodb'; + +import {isObject} from '@functional-abstraction/type'; + +import type Collection from '../Collection'; +import type Document from '../Document'; + +import {type Options} from '../transaction/TransactionDriver'; +import withSession from '../transaction/withSession'; +import withTransactionDriver from '../transaction/withTransactionDriver'; + +import {type EventEmitter, eventEmitter} from '../../lib/events'; + +import type Filter from './Filter'; + +const _watchInit = async ( + collection: Collection, + filter: Filter, + options: Options, + transactionOptions?: TransactionOptions, + sessionOptions?: ClientSessionOptions, +) => + withSession( + async (session) => + withTransactionDriver( + session, + async (driver) => { + const init = await driver.fetch(collection, filter, options); + const {operationTime} = session; + assert(operationTime !== undefined); + return {init, operationTime}; + }, + transactionOptions, + ), + sessionOptions, + ); + +const _filterToFullDocumentFilter = ( + operationKey: string, + filter: Filter, +) => + Object.fromEntries( + Object.entries(filter).map(([key, value]) => [ + key.startsWith('$') ? key : `${operationKey}.${key}`, + isObject(value) + ? _filterToFullDocumentFilter(operationKey, value as Filter) + : value, + ]), + ); + +const _filterToMatch = (filter: Filter) => ({ + $match: { + $or: [ + _filterToFullDocumentFilter('fullDocument', filter), + _filterToFullDocumentFilter('fullDocumentBeforeChange', filter), + { + $and: [ + {fullDocument: undefined}, + {fullDocumentBeforeChange: undefined}, + ], + }, + ], + }, +}); + +const _filterToPipeline = ({$text, ...rest}: Filter) => { + return { + pipeline: [_filterToMatch(rest as Filter)].filter(Boolean), + // TODO Any occurrence of $text should yield this, not just top-level. + isSuperset: $text !== undefined, + }; +}; + +const _optionsToPipeline = (options: Options) => + options.project === undefined ? [] : [{$project: options.project}]; + +const _watchStream = ( + collection: Collection, + filter: Filter, + options: Options, + startAtOperationTime: Timestamp, + changeStreamOptions?: ChangeStreamOptions, +) => { + const {pipeline: filterPipeline, isSuperset: filterIsSuperset} = + _filterToPipeline(filter); + + const pipeline = [...filterPipeline, ..._optionsToPipeline(options)]; + const stream = collection.rawCollection().watch(pipeline, { + startAtOperationTime, + fullDocument: 'whenAvailable', + fullDocumentBeforeChange: 'whenAvailable', + ...changeStreamOptions, + }); + + return { + stream, + isSuperset: filterIsSuperset, + }; +}; + +const _watchSetup = async ( + collection: Collection, + filter: Filter, + options: Options, + changeStreamOptions?: ChangeStreamOptions, + transactionOptions?: TransactionOptions, + sessionOptions?: ClientSessionOptions, +) => { + const {init, operationTime} = await _watchInit( + collection, + filter, + options, + transactionOptions, + sessionOptions, + ); + + const {stream, isSuperset: streamIsSuperset} = _watchStream( + collection, + filter, + options, + operationTime, + changeStreamOptions, + ); + + return {init, stream, streamIsSuperset}; +}; + +const _makeQueue = async () => { + let queued = 0; + let queue = new Promise((resolve) => { + resolve(undefined); + }); + await queue; + + const enqueue = (task: () => Promise | void) => { + // TODO Throttle. + if (queued !== 0) return; + ++queued; + queue = queue + .then(async () => { + --queued; + return task(); + }) + .catch((error) => { + console.error({error}); + }); + }; + + return enqueue; +}; + +export type WatchHandle = EventEmitter<{ + change: T[]; + start: undefined; + stop: undefined; +}>; + +const _watch = async ( + handle: WatchHandle, + collection: Collection, + filter: Filter, + options: Options, + changeStreamOptions?: ChangeStreamOptions, + transactionOptions?: TransactionOptions, + sessionOptions?: ClientSessionOptions, +) => { + const {init, stream} = await _watchSetup( + collection, + filter, + options, + changeStreamOptions, + transactionOptions, + sessionOptions, + ); + + const enqueue = await _makeQueue(); + + await handle.emitSerial('change', init); + + stream.on('change', () => { + enqueue(async () => { + const {init} = await _watchInit( + collection, + filter, + options, + transactionOptions, + sessionOptions, + ); + + await handle.emitSerial('change', init); + }); + }); + + // TODO stream.on('stop', ???) + const stop = async () => stream.close(); + + return stop; +}; + +const watch = async ( + collection: Collection, + filter: Filter, + options: Options, + changeStreamOptions?: ChangeStreamOptions, + transactionOptions?: TransactionOptions, + sessionOptions?: ClientSessionOptions, +) => { + const handle = eventEmitter<{ + change: T[]; + start: undefined; + stop: undefined; + }>(); + + let stopped = false; + + void handle.once('stop').then(() => { + stopped = true; + }); + + handle.on('start', async () => { + if (stopped) return; + const stop = await _watch( + handle, + collection, + filter, + options, + changeStreamOptions, + transactionOptions, + sessionOptions, + ); + if (stopped) await stop(); + else void handle.once('stop').then(stop); + }); + + return handle; +}; + +export default watch; diff --git a/imports/api/stats.ts b/imports/api/stats.ts index 106021b94..e55f34dc0 100644 --- a/imports/api/stats.ts +++ b/imports/api/stats.ts @@ -1,15 +1,16 @@ -import {type Subscription} from 'meteor/meteor'; - import schema from '../lib/schema'; import type Optional from '../lib/types/Optional'; +import {type Context} from './publication/Context'; + import {countCollection, type PollResult} from './collection/stats'; import define from './publication/define'; import type Collection from './Collection'; import type Document from './Document'; import {AuthenticationLoggedIn} from './Authentication'; -import type Selector from './query/Selector'; import type UserFilter from './query/UserFilter'; +import observeSetChanges from './query/observeSetChanges'; +import type Filter from './query/Filter'; export const countPublicationName = ( QueriedCollection: Collection, @@ -53,10 +54,10 @@ const countPublication = ( QueriedCollection: Collection, {fields, discretize, values}: CountOptions, ) => - function (this: Subscription, filter: UserFilter | null) { + async function (this: Context, filter: UserFilter | null) { const collection = countCollection; const key = countPublicationKey(QueriedCollection, {values}, filter); - const selector = {...filter, owner: this.userId} as Selector; + const selector = {...filter, owner: this.userId} as Filter; const options = { fields: Object.fromEntries(fields.map((field) => [field, 1])), }; @@ -96,33 +97,38 @@ const countPublication = ( }; let initializing = true; - const handle = QueriedCollection.find(selector, options).observeChanges({ - added: (_id, object) => { - total += 1; - inc(object); - refs.set(_id, {...object}); - if (!initializing) { + const handle = await observeSetChanges( + QueriedCollection, + selector, + options, + { + added: (_id, object) => { + total += 1; + inc(object); + refs.set(_id, {...object}); + if (!initializing) { + this.changed(collection, key, state()); + } + }, + + changed: (_id, changes) => { + const previousObject = refs.get(_id); + dec(previousObject); + const newObject = {...previousObject, ...changes}; + inc(newObject); + refs.set(_id, newObject); this.changed(collection, key, state()); - } - }, + }, - changed: (_id, changes) => { - const previousObject = refs.get(_id); - dec(previousObject); - const newObject = {...previousObject, ...changes}; - inc(newObject); - refs.set(_id, newObject); - this.changed(collection, key, state()); - }, - - removed: (_id) => { - total -= 1; - const previousObject = refs.get(_id); - dec(previousObject); - refs.delete(_id); - this.changed(collection, key, state()); + removed: (_id) => { + total -= 1; + const previousObject = refs.get(_id); + dec(previousObject); + refs.delete(_id); + this.changed(collection, key, state()); + }, }, - }); + ); // Instead, we'll send one `added` message right after `observeChanges` has // returned, and mark the subscription as ready. @@ -133,8 +139,8 @@ const countPublication = ( // Stop observing the cursor when the client unsubscribes. Stopping a // subscription automatically takes care of sending the client any `removed` // messages. - this.onStop(() => { - handle.stop(); + this.onStop(async () => { + await handle.emit('stop'); }); }; diff --git a/imports/api/useNoShowsForPatient.tests.ts b/imports/api/useNoShowsForPatient.tests.ts new file mode 100644 index 000000000..82d388e2f --- /dev/null +++ b/imports/api/useNoShowsForPatient.tests.ts @@ -0,0 +1,218 @@ +import {renderHook, waitFor} from '@testing-library/react'; +import {range} from '@iterable-iterator/range'; + +import {assert} from 'chai'; + +import {startOfTomorrow, startOfYesterday} from 'date-fns'; + +import {client, randomPassword, randomUserId} from '../_test/fixtures'; + +import createUserWithPassword from './user/createUserWithPassword'; +import loginWithPassword from './user/loginWithPassword'; +import call from './endpoint/call'; +import {newAppointmentFormData} from './_dev/populate/appointments'; + +import appointmentsSchedule from './endpoint/appointments/schedule'; +import appointmentsCancel from './endpoint/appointments/cancel'; +import randomId from './randomId'; +import useNoShowsForPatient from './useNoShowsForPatient'; +import {newPatientFormData} from './_dev/populate/patients'; +import patientsInsert from './endpoint/patients/insert'; +import beginConsultation from './endpoint/appointments/beginConsultation'; +import appointmentsReschedule from './endpoint/appointments/reschedule'; + +client(__filename, () => { + it('should render when logged out', async () => { + const patientId = randomId(); + const {result} = renderHook(() => useNoShowsForPatient(patientId)); + assert.deepEqual(result.current, { + loading: true, + found: false, + value: undefined, + }); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + found: false, + value: undefined, + }); + }); + + it('should render when logged in', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const patientId = randomId(); + const {result} = renderHook(() => useNoShowsForPatient(patientId)); + assert.deepEqual(result.current, { + loading: true, + found: false, + value: undefined, + }); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + found: true, + value: 0, + }); + }); + + it('should have aggregate on load', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const patientId = await call(patientsInsert, newPatientFormData()); + + const yesterday = startOfYesterday(); + const tomorrow = startOfTomorrow(); + + for (const _ of range(3)) { + // eslint-disable-next-line no-await-in-loop + await call( + appointmentsSchedule, + newAppointmentFormData({ + datetime: yesterday, + patient: {_id: patientId}, + }), + ); + } + + for (const _ of range(2)) { + // eslint-disable-next-line no-await-in-loop + await call( + appointmentsSchedule, + newAppointmentFormData({ + datetime: tomorrow, + patient: {_id: patientId}, + }), + ); + } + + const {result} = renderHook(() => useNoShowsForPatient(patientId)); + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + found: true, + value: 3, + }); + }); + + it('should react to changes', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const patientId = await call(patientsInsert, newPatientFormData()); + + const otherPatientId = await call(patientsInsert, newPatientFormData()); + + const yesterday = startOfYesterday(); + const tomorrow = startOfTomorrow(); + const {result} = renderHook(() => useNoShowsForPatient(patientId)); + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + found: true, + value: 0, + }); + + const _insertOneNoShow = async () => { + await call( + appointmentsSchedule, + newAppointmentFormData({ + datetime: tomorrow, + patient: {_id: patientId}, + }), + ); + + const {_id} = await call( + appointmentsSchedule, + newAppointmentFormData({ + datetime: yesterday, + patient: {_id: patientId}, + }), + ); + + await call( + appointmentsSchedule, + newAppointmentFormData({ + datetime: tomorrow, + patient: {_id: patientId}, + }), + ); + + return _id; + }; + + const a = await _insertOneNoShow(); + + await waitFor(() => { + assert.strictEqual(result.current.value, 1); + }); + + const b = await _insertOneNoShow(); + + await waitFor(() => { + assert.strictEqual(result.current.value, 2); + }); + + const c = await _insertOneNoShow(); + + await waitFor(() => { + assert.strictEqual(result.current.value, 3); + }); + + const d = await _insertOneNoShow(); + + await waitFor(() => { + assert.deepEqual(result.current, { + loading: false, + found: true, + value: 4, + }); + }); + + await call(appointmentsReschedule, d, {patient: {_id: otherPatientId}}); + + await waitFor(() => { + assert.strictEqual(result.current.value, 3); + }); + + await call(appointmentsCancel, b, '', ''); + + await waitFor(() => { + assert.strictEqual(result.current.value, 2); + }); + + await call(beginConsultation, a); + + await waitFor(() => { + assert.strictEqual(result.current.value, 1); + }); + + await call(appointmentsReschedule, c, {datetime: tomorrow, duration: 1}); + + await waitFor(() => { + assert.strictEqual(result.current.value, 0); + }); + }); +}); diff --git a/imports/api/user/createUserWithPassword.ts b/imports/api/user/createUserWithPassword.ts index 6671272ad..50b50c284 100644 --- a/imports/api/user/createUserWithPassword.ts +++ b/imports/api/user/createUserWithPassword.ts @@ -1,11 +1,8 @@ import {Accounts} from 'meteor/accounts-base'; -const createUserWithPassword = async (username: string, password: string) => - new Promise((resolve, reject) => { - Accounts.createUser({username, password}, (err) => { - if (err) reject(err); - else resolve(); - }); - }); +const createUserWithPassword = async ( + username: string, + password: string, +): Promise => Accounts.createUserAsync({username, password}); export default createUserWithPassword; diff --git a/imports/lib/events.ts b/imports/lib/events.ts new file mode 100644 index 000000000..bcb2603cd --- /dev/null +++ b/imports/lib/events.ts @@ -0,0 +1,4 @@ +import Emittery from 'emittery'; + +export type EventEmitter = Emittery; +export const eventEmitter = () => new Emittery(); diff --git a/imports/lib/iterable-iterator/duplicates.tests.ts b/imports/lib/iterable-iterator/duplicates.tests.ts new file mode 100644 index 000000000..1056a5f68 --- /dev/null +++ b/imports/lib/iterable-iterator/duplicates.tests.ts @@ -0,0 +1,25 @@ +import {assert} from 'chai'; + +import {isomorphic} from '../../_test/fixtures'; + +import duplicates from './duplicates'; + +isomorphic(__filename, () => { + it('should return nothing on input without duplicates', () => { + const expected = Array.from(''); + const actual = Array.from(duplicates('abcd')); + assert.deepEqual(actual, expected); + }); + + it('should work on empty inputs', () => { + const expected = []; + const actual = Array.from(duplicates([])); + assert.deepEqual(actual, expected); + }); + + it('should work', () => { + const expected = Array.from('aaabra'); + const actual = Array.from(duplicates('abracadabra')); + assert.deepEqual(actual, expected); + }); +}); diff --git a/imports/lib/iterable-iterator/duplicates.ts b/imports/lib/iterable-iterator/duplicates.ts new file mode 100644 index 000000000..6a8052e0d --- /dev/null +++ b/imports/lib/iterable-iterator/duplicates.ts @@ -0,0 +1,9 @@ +const duplicates = function* (items: Iterable): Generator { + const seen = new Set(); + for (const item of items) { + if (seen.has(item)) yield item; + else seen.add(item); + } +}; + +export default duplicates; diff --git a/imports/lib/iterable-iterator/unique.tests.ts b/imports/lib/iterable-iterator/unique.tests.ts new file mode 100644 index 000000000..2885de54c --- /dev/null +++ b/imports/lib/iterable-iterator/unique.tests.ts @@ -0,0 +1,25 @@ +import {assert} from 'chai'; + +import {isomorphic} from '../../_test/fixtures'; + +import unique from './unique'; + +isomorphic(__filename, () => { + it('should return nothing on input without duplicates', () => { + const expected = Array.from('abcd'); + const actual = Array.from(unique('abcd')); + assert.deepEqual(actual, expected); + }); + + it('should work on empty inputs', () => { + const expected = []; + const actual = Array.from(unique([])); + assert.deepEqual(actual, expected); + }); + + it('should work', () => { + const expected = Array.from('abrcd'); + const actual = Array.from(unique('abracadabra')); + assert.deepEqual(actual, expected); + }); +}); diff --git a/imports/lib/iterable-iterator/unique.ts b/imports/lib/iterable-iterator/unique.ts new file mode 100644 index 000000000..9eba0e8af --- /dev/null +++ b/imports/lib/iterable-iterator/unique.ts @@ -0,0 +1,3 @@ +const unique = (items: Iterable): Iterable => new Set(items); + +export default unique; diff --git a/imports/ui/availability/useAvailability.tests.ts b/imports/ui/availability/useAvailability.tests.ts new file mode 100644 index 000000000..131b662d8 --- /dev/null +++ b/imports/ui/availability/useAvailability.tests.ts @@ -0,0 +1,256 @@ +import {renderHook, waitFor} from '@testing-library/react'; + +import {assert} from 'chai'; + +import {addMilliseconds} from 'date-fns'; + +import { + client, + dropIds, + dropOwners, + randomPassword, + randomUserId, +} from '../../_test/fixtures'; +import createUserWithPassword from '../../api/user/createUserWithPassword'; +import loginWithPassword from '../../api/user/loginWithPassword'; +import call from '../../api/endpoint/call'; +import {newAppointmentFormData} from '../../api/_dev/populate/appointments'; + +import appointmentsSchedule from '../../api/endpoint/appointments/schedule'; + +import {beginningOfTime, endOfTime} from '../../lib/datetime'; +import {slot} from '../../api/availability'; +import appointmentsCancel from '../../api/endpoint/appointments/cancel'; + +import useAvailability from './useAvailability'; + +client(__filename, () => { + it('should render when logged out', async () => { + const {result} = renderHook(() => + useAvailability(beginningOfTime(), endOfTime(), {}, {}, []), + ); + assert.deepEqual(result.current, { + loading: true, + results: [], + }); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + results: [], + }); + }); + + it('should render when logged in', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const {result} = renderHook(() => + useAvailability(beginningOfTime(), endOfTime(), {}, {}, []), + ); + assert.deepEqual(result.current, { + loading: true, + results: [], + }); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + // TODO Should be [{beginningOfTime, endOfTime}] + results: [], + }); + }); + + it('should have aggregate on load', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const datetime = new Date(); + const duration = 12_345; + + await call( + appointmentsSchedule, + newAppointmentFormData({ + datetime, + duration, + }), + ); + + const begin = datetime; + const end = addMilliseconds(datetime, duration); + + const {result} = renderHook(() => + useAvailability( + beginningOfTime(), + endOfTime(), + {}, + {sort: {begin: 1}}, + [], + ), + ); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(dropOwners(dropIds(result.current.results)), [ + slot(beginningOfTime(), begin, 0), + slot(begin, end, 1), + slot(end, endOfTime(), 0), + ]); + }); + + it('should react to changes', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const {result} = renderHook(() => + useAvailability( + beginningOfTime(), + endOfTime(), + {}, + {sort: {begin: 1}}, + [], + ), + ); + assert.deepEqual(result.current, { + loading: true, + results: [], + }); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + results: [], + }); + + const datetime = new Date(); + const duration = 12_345; + + const {_id: appointmentId} = await call( + appointmentsSchedule, + newAppointmentFormData({ + datetime, + duration, + }), + ); + + await waitFor(() => { + assert.isNotEmpty(result.current.results); + }); + + const begin = datetime; + const end = addMilliseconds(datetime, duration); + + assert.deepEqual(dropOwners(dropIds(result.current.results)), [ + slot(beginningOfTime(), begin, 0), + slot(begin, end, 1), + slot(end, endOfTime(), 0), + ]); + + await call(appointmentsCancel, appointmentId, '', ''); + + await waitFor(() => { + assert.lengthOf(result.current.results, 1); + }); + + assert.deepEqual(dropOwners(dropIds(result.current.results)), [ + slot(beginningOfTime(), endOfTime(), 0), + ]); + }); + + it('should allow to filter by weight', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const datetime = new Date(); + const duration = 12_345; + + await call( + appointmentsSchedule, + newAppointmentFormData({ + datetime, + duration, + }), + ); + + const begin = datetime; + const end = addMilliseconds(datetime, duration); + + const {result} = renderHook(() => + useAvailability( + beginningOfTime(), + endOfTime(), + {weight: 0}, + {sort: {begin: 1}}, + [], + ), + ); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(dropOwners(dropIds(result.current.results)), [ + slot(beginningOfTime(), begin, 0), + slot(end, endOfTime(), 0), + ]); + }); + + it('should allow to filter intersection', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const datetime = new Date(); + const duration = 12_345; + + await call( + appointmentsSchedule, + newAppointmentFormData({ + datetime, + duration, + }), + ); + + const begin = datetime; + const end = addMilliseconds(datetime, duration); + + const {result} = renderHook(() => + useAvailability( + begin, + addMilliseconds(end, 1), + {}, + {sort: {begin: 1}}, + [], + ), + ); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(dropOwners(dropIds(result.current.results)), [ + slot(begin, end, 1), + slot(end, endOfTime(), 0), + ]); + }); +}); diff --git a/imports/ui/events/useIntersectingEvents.tests.ts b/imports/ui/events/useIntersectingEvents.tests.ts new file mode 100644 index 000000000..f910e274b --- /dev/null +++ b/imports/ui/events/useIntersectingEvents.tests.ts @@ -0,0 +1,258 @@ +import {renderHook, waitFor} from '@testing-library/react'; + +import {assert} from 'chai'; + +import {addMilliseconds} from 'date-fns'; + +import {list} from '@iterable-iterator/list'; +import {map} from '@iterable-iterator/map'; + +import {client, randomPassword, randomUserId} from '../../_test/fixtures'; +import createUserWithPassword from '../../api/user/createUserWithPassword'; +import loginWithPassword from '../../api/user/loginWithPassword'; +import call from '../../api/endpoint/call'; +import {newAppointmentFormData} from '../../api/_dev/populate/appointments'; + +import appointmentsSchedule from '../../api/endpoint/appointments/schedule'; + +import {beginningOfTime, endOfTime} from '../../lib/datetime'; +import appointmentsCancel from '../../api/endpoint/appointments/cancel'; + +import useIntersectingEvents from './useIntersectingEvents'; + +client(__filename, () => { + it('should render when logged out', async () => { + const {result} = renderHook(() => + useIntersectingEvents(beginningOfTime(), endOfTime(), {}, {}, []), + ); + assert.deepEqual(result.current, { + loading: true, + results: [], + }); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + results: [], + }); + }); + + it('should render when logged in', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const {result} = renderHook(() => + useIntersectingEvents(beginningOfTime(), endOfTime(), {}, {}, []), + ); + assert.deepEqual(result.current, { + loading: true, + results: [], + }); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + results: [], + }); + }); + + it('should have aggregate on load', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const datetime = new Date(); + const duration = 12_345; + + await call( + appointmentsSchedule, + newAppointmentFormData({ + datetime, + duration, + }), + ); + + const begin = datetime; + const end = addMilliseconds(datetime, duration); + + const {result} = renderHook(() => + useIntersectingEvents( + beginningOfTime(), + endOfTime(), + {}, + {sort: {begin: 1}}, + [], + ), + ); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual( + list(map(({begin, end}) => ({begin, end}), result.current.results)), + [{begin, end}], + ); + }); + + it('should handle empty intervals', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const datetime = new Date(); + const duration = 12_345; + + await call( + appointmentsSchedule, + newAppointmentFormData({ + datetime, + duration, + }), + ); + + const {result} = renderHook(() => + useIntersectingEvents(endOfTime(), beginningOfTime(), {}, {}, []), + ); + assert.deepEqual(result.current, { + loading: true, + results: [], + }); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + results: [], + }); + }); + + it('should react to changes', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const {result} = renderHook(() => + useIntersectingEvents( + beginningOfTime(), + endOfTime(), + {}, + {sort: {begin: 1}}, + [], + ), + ); + assert.deepEqual(result.current, { + loading: true, + results: [], + }); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + results: [], + }); + + const datetime = new Date(); + const duration = 12_345; + + const {_id: appointmentId} = await call( + appointmentsSchedule, + newAppointmentFormData({ + datetime, + duration, + }), + ); + + await waitFor(() => { + assert.isNotEmpty(result.current.results); + }); + + const begin = datetime; + const end = addMilliseconds(datetime, duration); + + assert.deepEqual( + list(map(({begin, end}) => ({begin, end}), result.current.results)), + [{begin, end}], + ); + + await call(appointmentsCancel, appointmentId, '', ''); + + await waitFor(() => { + assert(result.current.results[0]!.isCancelled); + }); + + assert.deepEqual( + list( + map( + ({begin, end, isCancelled}) => ({begin, end, isCancelled}), + result.current.results, + ), + ), + [{begin, end, isCancelled: true}], + ); + }); + + it('should allow to filter intersection', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const datetime = new Date(); + const duration = 12_345; + + await call( + appointmentsSchedule, + newAppointmentFormData({ + datetime, + duration, + }), + ); + + await call( + appointmentsSchedule, + newAppointmentFormData({ + datetime, + duration: 1, + }), + ); + + const begin = datetime; + const end = addMilliseconds(datetime, duration); + + const {result} = renderHook(() => + useIntersectingEvents( + addMilliseconds(begin, 1), + addMilliseconds(end, 1), + {}, + {sort: {begin: 1}}, + [], + ), + ); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual( + list(map(({begin, end}) => ({begin, end}), result.current.results)), + [{begin, end}], + ); + }); +}); diff --git a/imports/ui/stats/useFrequencyStats.tests.ts b/imports/ui/stats/useFrequencyStats.tests.ts new file mode 100644 index 000000000..c52e20d8e --- /dev/null +++ b/imports/ui/stats/useFrequencyStats.tests.ts @@ -0,0 +1,332 @@ +import {renderHook, waitFor} from '@testing-library/react'; + +import {assert} from 'chai'; + +import {client, randomPassword, randomUserId} from '../../_test/fixtures'; +import createUserWithPassword from '../../api/user/createUserWithPassword'; +import loginWithPassword from '../../api/user/loginWithPassword'; +import patientsInsert from '../../api/endpoint/patients/insert'; +import call from '../../api/endpoint/call'; +import {newPatientFormData} from '../../api/_dev/populate/patients'; +import {newConsultationFormData} from '../../api/_dev/populate/consultations'; +import consultationsInsert from '../../api/endpoint/consultations/insert'; +import patientsRemove from '../../api/endpoint/patients/remove'; +import consultationsRemove from '../../api/endpoint/consultations/remove'; + +import patientsUpdate from '../../api/endpoint/patients/update'; + +import useFrequencyStats from './useFrequencyStats'; + +client(__filename, () => { + it('should render when logged out', async () => { + const {result} = renderHook(() => useFrequencyStats()); + assert.deepEqual(result.current, { + loading: true, + total: undefined, + count: undefined, + }); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + total: undefined, + count: undefined, + }); + }); + + it('should render when logged in', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const {result} = renderHook(() => useFrequencyStats()); + assert.deepEqual(result.current, { + loading: true, + total: undefined, + count: undefined, + }); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 0, + count: [{}], + }); + }); + + it('should have aggregate on load', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const patientAId = await call( + patientsInsert, + newPatientFormData({sex: 'female'}), + ); + const patientBId = await call( + patientsInsert, + newPatientFormData({sex: 'male'}), + ); + + await call( + consultationsInsert, + newConsultationFormData({patientId: patientAId}), + ); + await call( + consultationsInsert, + newConsultationFormData({patientId: patientBId}), + ); + await call( + consultationsInsert, + newConsultationFormData({patientId: patientAId}), + ); + await call( + consultationsInsert, + newConsultationFormData({patientId: patientBId}), + ); + + const {result} = renderHook(() => useFrequencyStats()); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 4, + count: [{}, {}, {female: 1, male: 1}], + }); + }); + + it('should react to changes', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const {result} = renderHook(() => useFrequencyStats()); + assert.deepEqual(result.current, { + loading: true, + total: undefined, + count: undefined, + }); + + await waitFor(() => { + assert(!result.current.loading); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 0, + count: [{}], + }); + + const patientAId = await call( + patientsInsert, + newPatientFormData({sex: 'female'}), + ); + + await waitFor(() => { + assert.notDeepEqual(result.current.count, [{}]); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 0, + count: [{female: 1}], + }); + + const patientBId = await call( + patientsInsert, + newPatientFormData({sex: undefined}), + ); + + await waitFor(() => { + assert.notDeepEqual(result.current.count, [{female: 1}]); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 0, + count: [{female: 1, undefined: 1}], + }); + + await call( + consultationsInsert, + newConsultationFormData({patientId: patientAId}), + ); + + await waitFor(() => { + assert.strictEqual(result.current.total, 1); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 1, + count: [{undefined: 1}, {female: 1}], + }); + + const {insertedId: consultationAId} = await call( + consultationsInsert, + newConsultationFormData({patientId: patientBId}), + ); + const {insertedId: consultationBId} = await call( + consultationsInsert, + newConsultationFormData({patientId: patientBId}), + ); + + await waitFor(() => { + assert.strictEqual(result.current.total, 3); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 3, + count: [{}, {female: 1}, {undefined: 1}], + }); + + await call( + consultationsInsert, + newConsultationFormData({patientId: patientAId}), + ); + + await waitFor(() => { + assert.strictEqual(result.current.total, 4); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 4, + count: [{}, {}, {female: 1, undefined: 1}], + }); + + await call(patientsRemove, patientAId); + + await waitFor(() => { + assert.strictEqual(result.current.total, 2); + }); + await waitFor(() => { + assert.deepEqual(result.current.count![0], {}); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 2, + count: [{}, {}, {undefined: 1}], + }); + + await call(consultationsRemove, consultationAId); + + await waitFor(() => { + assert.strictEqual(result.current.total, 1); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 1, + count: [{}, {undefined: 1}, {}], + }); + + await call(consultationsRemove, consultationBId); + + await waitFor(() => { + assert.strictEqual(result.current.total, 0); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 0, + count: [{undefined: 1}, {}, {}], + }); + }); + + it('should handle `other` patient sex', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const {result} = renderHook(() => useFrequencyStats()); + + await call(patientsInsert, newPatientFormData({sex: 'other'})); + + await waitFor(() => { + assert.notDeepEqual(result.current.count, [{}]); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 0, + count: [{other: 1}], + }); + }); + + it('should handle patient sex', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const {result} = renderHook(() => useFrequencyStats()); + + await call(patientsInsert, newPatientFormData({sex: ''})); + + await waitFor(() => { + assert.notDeepEqual(result.current.count, [{}]); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 0, + count: [{'': 1}], + }); + }); + + it('should handle patient sex update', async () => { + const username = randomUserId(); + const password = randomPassword(); + await createUserWithPassword(username, password); + await loginWithPassword(username, password); + + const {result} = renderHook(() => useFrequencyStats()); + + const patientId = await call( + patientsInsert, + newPatientFormData({sex: 'male'}), + ); + + await call(consultationsInsert, newConsultationFormData({patientId})); + + await waitFor(() => { + assert.strictEqual(result.current.total, 1); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 1, + count: [{}, {male: 1}], + }); + + await call(patientsUpdate, patientId, {sex: 'other'}); + + await call(consultationsInsert, newConsultationFormData({patientId})); + + await waitFor(() => { + assert.strictEqual(result.current.total, 2); + }); + + assert.deepEqual(result.current, { + loading: false, + total: 2, + count: [{}, {}, {other: 1}], + }); + }); +}); diff --git a/package-lock.json b/package-lock.json index 485c9ff2d..9b9f29b93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,550 +34,548 @@ "resolved": "https://registry.npmjs.org/@async-iterable-iterator/async-iterator-to-array/-/async-iterator-to-array-0.0.1.tgz", "integrity": "sha512-VaFBhYBdTJ4DdVblOmZRjDMzPFzf46lm/hA7rMqWYguArQHho0wGe8gADpraXqD2REwGL0q/FvO8cnZ9+rMoUQ==" }, - "@aws-crypto/ie11-detection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", - "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", - "dev": true, - "requires": { - "tslib": "^1.11.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, "@aws-crypto/sha256-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", - "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", "dev": true, + "optional": true, "requires": { - "@aws-crypto/ie11-detection": "^3.0.0", - "@aws-crypto/sha256-js": "^3.0.0", - "@aws-crypto/supports-web-crypto": "^3.0.0", - "@aws-crypto/util": "^3.0.0", + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" }, "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dev": true, + "optional": true, + "requires": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + } } } }, "@aws-crypto/sha256-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", - "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", "dev": true, + "optional": true, "requires": { - "@aws-crypto/util": "^3.0.0", + "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", - "tslib": "^1.11.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } + "tslib": "^2.6.2" } }, "@aws-crypto/supports-web-crypto": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", - "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", "dev": true, + "optional": true, "requires": { - "tslib": "^1.11.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } + "tslib": "^2.6.2" } }, "@aws-crypto/util": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", - "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", "dev": true, + "optional": true, "requires": { "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" }, "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dev": true, + "optional": true, + "requires": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + } } } }, "@aws-sdk/client-cognito-identity": { - "version": "3.590.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.590.0.tgz", - "integrity": "sha512-Nfn23x7yZgp1umB+Avvsw9t8XIFWEqNQcpJ10Q8RcI9bQ0SvR4OcnnVsBA0WFL53FVzVM2FAkjNrCMRaSe6xWw==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.609.0.tgz", + "integrity": "sha512-3kDTpia1iN/accayoH3MbZRbDvX2tzrKrBTU7wNNoazVrh+gOMS8KCOWrOB72F0V299l4FsfQhnl9BDMVrc1iw==", "dev": true, "optional": true, "requires": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sso-oidc": "3.590.0", - "@aws-sdk/client-sts": "3.590.0", - "@aws-sdk/core": "3.588.0", - "@aws-sdk/credential-provider-node": "3.590.0", - "@aws-sdk/middleware-host-header": "3.577.0", - "@aws-sdk/middleware-logger": "3.577.0", - "@aws-sdk/middleware-recursion-detection": "3.577.0", - "@aws-sdk/middleware-user-agent": "3.587.0", - "@aws-sdk/region-config-resolver": "3.587.0", - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.587.0", - "@aws-sdk/util-user-agent-browser": "3.577.0", - "@aws-sdk/util-user-agent-node": "3.587.0", - "@smithy/config-resolver": "^3.0.1", - "@smithy/core": "^2.1.1", - "@smithy/fetch-http-handler": "^3.0.1", - "@smithy/hash-node": "^3.0.0", - "@smithy/invalid-dependency": "^3.0.0", - "@smithy/middleware-content-length": "^3.0.0", - "@smithy/middleware-endpoint": "^3.0.1", - "@smithy/middleware-retry": "^3.0.3", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/node-config-provider": "^3.1.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.1.1", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.609.0", + "@aws-sdk/client-sts": "3.609.0", + "@aws-sdk/core": "3.609.0", + "@aws-sdk/credential-provider-node": "3.609.0", + "@aws-sdk/middleware-host-header": "3.609.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.609.0", + "@aws-sdk/middleware-user-agent": "3.609.0", + "@aws-sdk/region-config-resolver": "3.609.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.609.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.609.0", + "@smithy/config-resolver": "^3.0.4", + "@smithy/core": "^2.2.4", + "@smithy/fetch-http-handler": "^3.2.0", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.3", + "@smithy/middleware-endpoint": "^3.0.4", + "@smithy/middleware-retry": "^3.0.7", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.3", + "@smithy/node-http-handler": "^3.1.1", + "@smithy/protocol-http": "^4.0.3", + "@smithy/smithy-client": "^3.1.5", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.3", - "@smithy/util-defaults-mode-node": "^3.0.3", - "@smithy/util-endpoints": "^2.0.1", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.7", + "@smithy/util-defaults-mode-node": "^3.0.7", + "@smithy/util-endpoints": "^2.0.4", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "@aws-sdk/client-sso": { - "version": "3.590.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.590.0.tgz", - "integrity": "sha512-6xbC6oQVJKBRTyXyR3C15ksUsPOyW4p+uCj7dlKYWGJvh4vGTV8KhZKS53oPG8t4f1+OMJWjr5wKuXRoaFsmhQ==", - "dev": true, - "requires": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/core": "3.588.0", - "@aws-sdk/middleware-host-header": "3.577.0", - "@aws-sdk/middleware-logger": "3.577.0", - "@aws-sdk/middleware-recursion-detection": "3.577.0", - "@aws-sdk/middleware-user-agent": "3.587.0", - "@aws-sdk/region-config-resolver": "3.587.0", - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.587.0", - "@aws-sdk/util-user-agent-browser": "3.577.0", - "@aws-sdk/util-user-agent-node": "3.587.0", - "@smithy/config-resolver": "^3.0.1", - "@smithy/core": "^2.1.1", - "@smithy/fetch-http-handler": "^3.0.1", - "@smithy/hash-node": "^3.0.0", - "@smithy/invalid-dependency": "^3.0.0", - "@smithy/middleware-content-length": "^3.0.0", - "@smithy/middleware-endpoint": "^3.0.1", - "@smithy/middleware-retry": "^3.0.3", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/node-config-provider": "^3.1.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.1.1", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.609.0.tgz", + "integrity": "sha512-gqXGFDkIpKHCKAbeJK4aIDt3tiwJ26Rf5Tqw9JS6BYXsdMeOB8FTzqD9R+Yc1epHd8s5L94sdqXT5PapgxFZrg==", + "dev": true, + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.609.0", + "@aws-sdk/middleware-host-header": "3.609.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.609.0", + "@aws-sdk/middleware-user-agent": "3.609.0", + "@aws-sdk/region-config-resolver": "3.609.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.609.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.609.0", + "@smithy/config-resolver": "^3.0.4", + "@smithy/core": "^2.2.4", + "@smithy/fetch-http-handler": "^3.2.0", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.3", + "@smithy/middleware-endpoint": "^3.0.4", + "@smithy/middleware-retry": "^3.0.7", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.3", + "@smithy/node-http-handler": "^3.1.1", + "@smithy/protocol-http": "^4.0.3", + "@smithy/smithy-client": "^3.1.5", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.3", - "@smithy/util-defaults-mode-node": "^3.0.3", - "@smithy/util-endpoints": "^2.0.1", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.7", + "@smithy/util-defaults-mode-node": "^3.0.7", + "@smithy/util-endpoints": "^2.0.4", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "@aws-sdk/client-sso-oidc": { - "version": "3.590.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.590.0.tgz", - "integrity": "sha512-3yCLPjq6WFfDpdUJKk/gSz4eAPDTjVknXaveMPi2QoVBCshneOnJsV16uNKlpVF1frTHrrDRfKYmbaVh6nFBvQ==", - "dev": true, - "requires": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.590.0", - "@aws-sdk/core": "3.588.0", - "@aws-sdk/credential-provider-node": "3.590.0", - "@aws-sdk/middleware-host-header": "3.577.0", - "@aws-sdk/middleware-logger": "3.577.0", - "@aws-sdk/middleware-recursion-detection": "3.577.0", - "@aws-sdk/middleware-user-agent": "3.587.0", - "@aws-sdk/region-config-resolver": "3.587.0", - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.587.0", - "@aws-sdk/util-user-agent-browser": "3.577.0", - "@aws-sdk/util-user-agent-node": "3.587.0", - "@smithy/config-resolver": "^3.0.1", - "@smithy/core": "^2.1.1", - "@smithy/fetch-http-handler": "^3.0.1", - "@smithy/hash-node": "^3.0.0", - "@smithy/invalid-dependency": "^3.0.0", - "@smithy/middleware-content-length": "^3.0.0", - "@smithy/middleware-endpoint": "^3.0.1", - "@smithy/middleware-retry": "^3.0.3", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/node-config-provider": "^3.1.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.1.1", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.609.0.tgz", + "integrity": "sha512-0bNPAyPdkWkS9EGB2A9BZDkBNrnVCBzk5lYRezoT4K3/gi9w1DTYH5tuRdwaTZdxW19U1mq7CV0YJJARKO1L9Q==", + "dev": true, + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.609.0", + "@aws-sdk/credential-provider-node": "3.609.0", + "@aws-sdk/middleware-host-header": "3.609.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.609.0", + "@aws-sdk/middleware-user-agent": "3.609.0", + "@aws-sdk/region-config-resolver": "3.609.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.609.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.609.0", + "@smithy/config-resolver": "^3.0.4", + "@smithy/core": "^2.2.4", + "@smithy/fetch-http-handler": "^3.2.0", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.3", + "@smithy/middleware-endpoint": "^3.0.4", + "@smithy/middleware-retry": "^3.0.7", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.3", + "@smithy/node-http-handler": "^3.1.1", + "@smithy/protocol-http": "^4.0.3", + "@smithy/smithy-client": "^3.1.5", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.3", - "@smithy/util-defaults-mode-node": "^3.0.3", - "@smithy/util-endpoints": "^2.0.1", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.7", + "@smithy/util-defaults-mode-node": "^3.0.7", + "@smithy/util-endpoints": "^2.0.4", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "@aws-sdk/client-sts": { - "version": "3.590.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.590.0.tgz", - "integrity": "sha512-f4R1v1LSn4uLYZ5qj4DyL6gp7PXXzJeJsm2seheiJX+53LSF5L7XSDnQVtX1p9Tevv0hp2YUWUTg6QYwIVSuGg==", - "dev": true, - "requires": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sso-oidc": "3.590.0", - "@aws-sdk/core": "3.588.0", - "@aws-sdk/credential-provider-node": "3.590.0", - "@aws-sdk/middleware-host-header": "3.577.0", - "@aws-sdk/middleware-logger": "3.577.0", - "@aws-sdk/middleware-recursion-detection": "3.577.0", - "@aws-sdk/middleware-user-agent": "3.587.0", - "@aws-sdk/region-config-resolver": "3.587.0", - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.587.0", - "@aws-sdk/util-user-agent-browser": "3.577.0", - "@aws-sdk/util-user-agent-node": "3.587.0", - "@smithy/config-resolver": "^3.0.1", - "@smithy/core": "^2.1.1", - "@smithy/fetch-http-handler": "^3.0.1", - "@smithy/hash-node": "^3.0.0", - "@smithy/invalid-dependency": "^3.0.0", - "@smithy/middleware-content-length": "^3.0.0", - "@smithy/middleware-endpoint": "^3.0.1", - "@smithy/middleware-retry": "^3.0.3", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/node-config-provider": "^3.1.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.1.1", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.609.0.tgz", + "integrity": "sha512-A0B3sDKFoFlGo8RYRjDBWHXpbgirer2bZBkCIzhSPHc1vOFHt/m2NcUoE2xnBKXJFrptL1xDkvo1P+XYp/BfcQ==", + "dev": true, + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.609.0", + "@aws-sdk/core": "3.609.0", + "@aws-sdk/credential-provider-node": "3.609.0", + "@aws-sdk/middleware-host-header": "3.609.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.609.0", + "@aws-sdk/middleware-user-agent": "3.609.0", + "@aws-sdk/region-config-resolver": "3.609.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.609.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.609.0", + "@smithy/config-resolver": "^3.0.4", + "@smithy/core": "^2.2.4", + "@smithy/fetch-http-handler": "^3.2.0", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.3", + "@smithy/middleware-endpoint": "^3.0.4", + "@smithy/middleware-retry": "^3.0.7", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.3", + "@smithy/node-http-handler": "^3.1.1", + "@smithy/protocol-http": "^4.0.3", + "@smithy/smithy-client": "^3.1.5", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.3", - "@smithy/util-defaults-mode-node": "^3.0.3", - "@smithy/util-endpoints": "^2.0.1", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.7", + "@smithy/util-defaults-mode-node": "^3.0.7", + "@smithy/util-endpoints": "^2.0.4", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "@aws-sdk/core": { - "version": "3.588.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.588.0.tgz", - "integrity": "sha512-O1c2+9ce46Z+iiid+W3iC1IvPbfIo5ev9CBi54GdNB9SaI8/3+f8MJcux0D6c9toCF0ArMersN/gp8ek57e9uQ==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.609.0.tgz", + "integrity": "sha512-ptqw+DTxLr01+pKjDUuo53SEDzI+7nFM3WfQaEo0yhDg8vWw8PER4sWj1Ysx67ksctnZesPUjqxd5SHbtdBxiA==", "dev": true, + "optional": true, "requires": { - "@smithy/core": "^2.1.1", - "@smithy/protocol-http": "^4.0.0", - "@smithy/signature-v4": "^3.0.0", - "@smithy/smithy-client": "^3.1.1", - "@smithy/types": "^3.0.0", + "@smithy/core": "^2.2.4", + "@smithy/protocol-http": "^4.0.3", + "@smithy/signature-v4": "^3.1.2", + "@smithy/smithy-client": "^3.1.5", + "@smithy/types": "^3.3.0", "fast-xml-parser": "4.2.5", "tslib": "^2.6.2" } }, "@aws-sdk/credential-provider-cognito-identity": { - "version": "3.590.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.590.0.tgz", - "integrity": "sha512-28vRC0BYaDVWU9AzGBywTRmwiwQfkixfOZGcY6e5J6cRjVoawomvHmC2mJd11SjoDcVLUQF+z4Z9z1ZCr1GcpA==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.609.0.tgz", + "integrity": "sha512-BqrpAXRr64dQ/uZsRB2wViGKTkVRlfp8Q+Zd7Bc8Ikk+YXjPtl+IyWXKtdKQ3LBO255KwAcPmra5oFC+2R1GOQ==", "dev": true, "optional": true, "requires": { - "@aws-sdk/client-cognito-identity": "3.590.0", - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.1.0", - "@smithy/types": "^3.0.0", + "@aws-sdk/client-cognito-identity": "3.609.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@aws-sdk/credential-provider-env": { - "version": "3.587.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.587.0.tgz", - "integrity": "sha512-Hyg/5KFECIk2k5o8wnVEiniV86yVkhn5kzITUydmNGCkXdBFHMHRx6hleQ1bqwJHbBskyu8nbYamzcwymmGwmw==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.609.0.tgz", + "integrity": "sha512-v69ZCWcec2iuV9vLVJMa6fAb5xwkzN4jYIT8yjo2c4Ia/j976Q+TPf35Pnz5My48Xr94EFcaBazrWedF+kwfuQ==", "dev": true, + "optional": true, "requires": { - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.1.0", - "@smithy/types": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@aws-sdk/credential-provider-http": { - "version": "3.587.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.587.0.tgz", - "integrity": "sha512-Su1SRWVRCuR1e32oxX3C1V4c5hpPN20WYcRfdcr2wXwHqSvys5DrnmuCC+JoEnS/zt3adUJhPliTqpfKgSdMrA==", - "dev": true, - "requires": { - "@aws-sdk/types": "3.577.0", - "@smithy/fetch-http-handler": "^3.0.1", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/property-provider": "^3.1.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.1.1", - "@smithy/types": "^3.0.0", - "@smithy/util-stream": "^3.0.1", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.609.0.tgz", + "integrity": "sha512-GQQfB9Mk4XUZwaPsk4V3w8MqleS6ApkZKVQn3vTLAKa8Y7B2Imcpe5zWbKYjDd8MPpMWjHcBGFTVlDRFP4zwSQ==", + "dev": true, + "optional": true, + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/fetch-http-handler": "^3.2.0", + "@smithy/node-http-handler": "^3.1.1", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.0.3", + "@smithy/smithy-client": "^3.1.5", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.0.5", "tslib": "^2.6.2" } }, "@aws-sdk/credential-provider-ini": { - "version": "3.590.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.590.0.tgz", - "integrity": "sha512-Y5cFciAK38VIvRgZeND7HvFNR32thGtQb8Xop6cMn33FC78uwcRIu9Hc9699XTclCZqz4+Xl1WU+dZ+rnFn2AA==", - "dev": true, - "requires": { - "@aws-sdk/credential-provider-env": "3.587.0", - "@aws-sdk/credential-provider-http": "3.587.0", - "@aws-sdk/credential-provider-process": "3.587.0", - "@aws-sdk/credential-provider-sso": "3.590.0", - "@aws-sdk/credential-provider-web-identity": "3.587.0", - "@aws-sdk/types": "3.577.0", - "@smithy/credential-provider-imds": "^3.1.0", - "@smithy/property-provider": "^3.1.0", - "@smithy/shared-ini-file-loader": "^3.1.0", - "@smithy/types": "^3.0.0", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.609.0.tgz", + "integrity": "sha512-hwaBfXuBTv6/eAdEsDfGcteYUW6Km7lvvubbxEdxIuJNF3vswR7RMGIXaEC37hhPkTTgd3H0TONammhwZIfkog==", + "dev": true, + "optional": true, + "requires": { + "@aws-sdk/credential-provider-env": "3.609.0", + "@aws-sdk/credential-provider-http": "3.609.0", + "@aws-sdk/credential-provider-process": "3.609.0", + "@aws-sdk/credential-provider-sso": "3.609.0", + "@aws-sdk/credential-provider-web-identity": "3.609.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.1.3", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@aws-sdk/credential-provider-node": { - "version": "3.590.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.590.0.tgz", - "integrity": "sha512-Ky38mNFoXobGrDQ11P3dU1e+q1nRJ7eZl8l15KUpvZCe/hOudbxQi/epQrCazD/gRYV2fTyczdLlZzB5ZZ8DhQ==", - "dev": true, - "requires": { - "@aws-sdk/credential-provider-env": "3.587.0", - "@aws-sdk/credential-provider-http": "3.587.0", - "@aws-sdk/credential-provider-ini": "3.590.0", - "@aws-sdk/credential-provider-process": "3.587.0", - "@aws-sdk/credential-provider-sso": "3.590.0", - "@aws-sdk/credential-provider-web-identity": "3.587.0", - "@aws-sdk/types": "3.577.0", - "@smithy/credential-provider-imds": "^3.1.0", - "@smithy/property-provider": "^3.1.0", - "@smithy/shared-ini-file-loader": "^3.1.0", - "@smithy/types": "^3.0.0", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.609.0.tgz", + "integrity": "sha512-4J8/JRuqfxJDGD9jTHVCBxCvYt7/Vgj2Stlhj930mrjFPO/yRw8ilAAZxBWe0JHPX3QwepCmh4ErZe53F5ysxQ==", + "dev": true, + "optional": true, + "requires": { + "@aws-sdk/credential-provider-env": "3.609.0", + "@aws-sdk/credential-provider-http": "3.609.0", + "@aws-sdk/credential-provider-ini": "3.609.0", + "@aws-sdk/credential-provider-process": "3.609.0", + "@aws-sdk/credential-provider-sso": "3.609.0", + "@aws-sdk/credential-provider-web-identity": "3.609.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.1.3", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@aws-sdk/credential-provider-process": { - "version": "3.587.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.587.0.tgz", - "integrity": "sha512-V4xT3iCqkF8uL6QC4gqBJg/2asd/damswP1h9HCfqTllmPWzImS+8WD3VjgTLw5b0KbTy+ZdUhKc0wDnyzkzxg==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.609.0.tgz", + "integrity": "sha512-Ux35nGOSJKZWUIM3Ny0ROZ8cqPRUEkh+tR3X2o9ydEbFiLq3eMMyEnHJqx4EeUjLRchidlm4CCid9GxMe5/gdw==", "dev": true, + "optional": true, "requires": { - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.1.0", - "@smithy/shared-ini-file-loader": "^3.1.0", - "@smithy/types": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@aws-sdk/credential-provider-sso": { - "version": "3.590.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.590.0.tgz", - "integrity": "sha512-v+0j/I+je9okfwXsgmLppmwIE+TuMp5WqLz7r7PHz9KjzLyKaKTDvfllFD+8oPpBqnmOWiJ9qTGPkrfhB7a/fQ==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.609.0.tgz", + "integrity": "sha512-oQPGDKMMIxjvTcm86g07RPYeC7mCNk+29dPpY15ZAPRpAF7F0tircsC3wT9fHzNaKShEyK5LuI5Kg/uxsdy+Iw==", "dev": true, + "optional": true, "requires": { - "@aws-sdk/client-sso": "3.590.0", - "@aws-sdk/token-providers": "3.587.0", - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.1.0", - "@smithy/shared-ini-file-loader": "^3.1.0", - "@smithy/types": "^3.0.0", + "@aws-sdk/client-sso": "3.609.0", + "@aws-sdk/token-providers": "3.609.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@aws-sdk/credential-provider-web-identity": { - "version": "3.587.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.587.0.tgz", - "integrity": "sha512-XqIx/I2PG7kyuw3WjAP9wKlxy8IvFJwB8asOFT1xPFoVfZYKIogjG9oLP5YiRtfvDkWIztHmg5MlVv3HdJDGRw==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.609.0.tgz", + "integrity": "sha512-U+PG8NhlYYF45zbr1km3ROtBMYqyyj/oK8NRp++UHHeuavgrP+4wJ4wQnlEaKvJBjevfo3+dlIBcaeQ7NYejWg==", "dev": true, + "optional": true, "requires": { - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.1.0", - "@smithy/types": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@aws-sdk/credential-providers": { - "version": "3.590.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.590.0.tgz", - "integrity": "sha512-Z4SHk/GCoM5JEJOH3+xr2I7VvPGdeGPHL1cck/UFIN1Fap1wT3uIsTW92Rhru2AvnhQnAPpDUOHO9/hDJk1MDA==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.609.0.tgz", + "integrity": "sha512-bJKMY4QwRVderh8R2s9kukoZhuNZew/xzwPa9DRRFVOIsznsS0faAdmAAFrKb8e06YyQq6DiZP0BfFyVHAXE2A==", "dev": true, "optional": true, "requires": { - "@aws-sdk/client-cognito-identity": "3.590.0", - "@aws-sdk/client-sso": "3.590.0", - "@aws-sdk/client-sts": "3.590.0", - "@aws-sdk/credential-provider-cognito-identity": "3.590.0", - "@aws-sdk/credential-provider-env": "3.587.0", - "@aws-sdk/credential-provider-http": "3.587.0", - "@aws-sdk/credential-provider-ini": "3.590.0", - "@aws-sdk/credential-provider-node": "3.590.0", - "@aws-sdk/credential-provider-process": "3.587.0", - "@aws-sdk/credential-provider-sso": "3.590.0", - "@aws-sdk/credential-provider-web-identity": "3.587.0", - "@aws-sdk/types": "3.577.0", - "@smithy/credential-provider-imds": "^3.1.0", - "@smithy/property-provider": "^3.1.0", - "@smithy/types": "^3.0.0", + "@aws-sdk/client-cognito-identity": "3.609.0", + "@aws-sdk/client-sso": "3.609.0", + "@aws-sdk/client-sts": "3.609.0", + "@aws-sdk/credential-provider-cognito-identity": "3.609.0", + "@aws-sdk/credential-provider-env": "3.609.0", + "@aws-sdk/credential-provider-http": "3.609.0", + "@aws-sdk/credential-provider-ini": "3.609.0", + "@aws-sdk/credential-provider-node": "3.609.0", + "@aws-sdk/credential-provider-process": "3.609.0", + "@aws-sdk/credential-provider-sso": "3.609.0", + "@aws-sdk/credential-provider-web-identity": "3.609.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.1.3", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@aws-sdk/middleware-host-header": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.577.0.tgz", - "integrity": "sha512-9ca5MJz455CODIVXs0/sWmJm7t3QO4EUa1zf8pE8grLpzf0J94bz/skDWm37Pli13T3WaAQBHCTiH2gUVfCsWg==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.609.0.tgz", + "integrity": "sha512-iTKfo158lc4jLDfYeZmYMIBHsn8m6zX+XB6birCSNZ/rrlzAkPbGE43CNdKfvjyWdqgLMRXF+B+OcZRvqhMXPQ==", "dev": true, + "optional": true, "requires": { - "@aws-sdk/types": "3.577.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.0.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@aws-sdk/middleware-logger": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.577.0.tgz", - "integrity": "sha512-aPFGpGjTZcJYk+24bg7jT4XdIp42mFXSuPt49lw5KygefLyJM/sB0bKKqPYYivW0rcuZ9brQ58eZUNthrzYAvg==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", + "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", "dev": true, + "optional": true, "requires": { - "@aws-sdk/types": "3.577.0", - "@smithy/types": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@aws-sdk/middleware-recursion-detection": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.577.0.tgz", - "integrity": "sha512-pn3ZVEd2iobKJlR3H+bDilHjgRnNrQ6HMmK9ZzZw89Ckn3Dcbv48xOv4RJvu0aU8SDLl/SNCxppKjeLDTPGBNA==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.609.0.tgz", + "integrity": "sha512-6sewsYB7/o/nbUfA99Aa/LokM+a/u4Wpm/X2o0RxOsDtSB795ObebLJe2BxY5UssbGaWkn7LswyfvrdZNXNj1w==", "dev": true, + "optional": true, "requires": { - "@aws-sdk/types": "3.577.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.0.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@aws-sdk/middleware-user-agent": { - "version": "3.587.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.587.0.tgz", - "integrity": "sha512-SyDomN+IOrygLucziG7/nOHkjUXES5oH5T7p8AboO8oakMQJdnudNXiYWTicQWO52R51U6CR27rcMPTGeMedYA==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.609.0.tgz", + "integrity": "sha512-nbq7MXRmeXm4IDqh+sJRAxGPAq0OfGmGIwKvJcw66hLoG8CmhhVMZmIAEBDFr57S+YajGwnLLRt+eMI05MMeVA==", "dev": true, + "optional": true, "requires": { - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.587.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.609.0", + "@smithy/protocol-http": "^4.0.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@aws-sdk/region-config-resolver": { - "version": "3.587.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.587.0.tgz", - "integrity": "sha512-93I7IPZtulZQoRK+O20IJ4a1syWwYPzoO2gc3v+/GNZflZPV3QJXuVbIm0pxBsu0n/mzKGUKqSOLPIaN098HcQ==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.609.0.tgz", + "integrity": "sha512-lMHBG8zg9GWYBc9/XVPKyuAUd7iKqfPP7z04zGta2kGNOKbUTeqmAdc1gJGku75p4kglIPlGBorOxti8DhRmKw==", "dev": true, + "optional": true, "requires": { - "@aws-sdk/types": "3.577.0", - "@smithy/node-config-provider": "^3.1.0", - "@smithy/types": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.3", + "@smithy/types": "^3.3.0", "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" } }, "@aws-sdk/token-providers": { - "version": "3.587.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.587.0.tgz", - "integrity": "sha512-ULqhbnLy1hmJNRcukANBWJmum3BbjXnurLPSFXoGdV0llXYlG55SzIla2VYqdveQEEjmsBuTZdFvXAtNpmS5Zg==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.609.0.tgz", + "integrity": "sha512-WvhW/7XSf+H7YmtiIigQxfDVZVZI7mbKikQ09YpzN7FeN3TmYib1+0tB+EE9TbICkwssjiFc71FEBEh4K9grKQ==", "dev": true, + "optional": true, "requires": { - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.1.0", - "@smithy/shared-ini-file-loader": "^3.1.0", - "@smithy/types": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@aws-sdk/types": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.577.0.tgz", - "integrity": "sha512-FT2JZES3wBKN/alfmhlo+3ZOq/XJ0C7QOZcDNrpKjB0kqYoKjhVKZ/Hx6ArR0czkKfHzBBEs6y40ebIHx2nSmA==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", "dev": true, + "optional": true, "requires": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@aws-sdk/util-endpoints": { - "version": "3.587.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.587.0.tgz", - "integrity": "sha512-8I1HG6Em8wQWqKcRW6m358mqebRVNpL8XrrEoT4In7xqkKkmYtHRNVYP6lcmiQh5pZ/c/FXu8dSchuFIWyEtqQ==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.609.0.tgz", + "integrity": "sha512-Rh+3V8dOvEeE1aQmUy904DYWtLUEJ7Vf5XBPlQ6At3pBhp+zpXbsnpZzVL33c8lW1xfj6YPwtO6gOeEsl1juCQ==", "dev": true, + "optional": true, "requires": { - "@aws-sdk/types": "3.577.0", - "@smithy/types": "^3.0.0", - "@smithy/util-endpoints": "^2.0.1", + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "@smithy/util-endpoints": "^2.0.4", "tslib": "^2.6.2" } }, @@ -586,49 +584,43 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.568.0.tgz", "integrity": "sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig==", "dev": true, + "optional": true, "requires": { "tslib": "^2.6.2" } }, "@aws-sdk/util-user-agent-browser": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.577.0.tgz", - "integrity": "sha512-zEAzHgR6HWpZOH7xFgeJLc6/CzMcx4nxeQolZxVZoB5pPaJd3CjyRhZN0xXeZB0XIRCWmb4yJBgyiugXLNMkLA==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", + "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", "dev": true, + "optional": true, "requires": { - "@aws-sdk/types": "3.577.0", - "@smithy/types": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "@aws-sdk/util-user-agent-node": { - "version": "3.587.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.587.0.tgz", - "integrity": "sha512-Pnl+DUe/bvnbEEDHP3iVJrOtE3HbFJBPgsD6vJ+ml/+IYk1Eq49jEG+EHZdNTPz3SDG0kbp2+7u41MKYJHR/iQ==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.609.0.tgz", + "integrity": "sha512-DlZBwQ/HkZyf3pOWc7+wjJRk5R7x9YxHhs2szHwtv1IW30KMabjjjX0GMlGJ9LLkBHkbaaEY/w9Tkj12XRLhRg==", "dev": true, + "optional": true, "requires": { - "@aws-sdk/types": "3.577.0", - "@smithy/node-config-provider": "^3.1.0", - "@smithy/types": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, - "@aws-sdk/util-utf8-browser": { - "version": "3.259.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", - "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", - "dev": true, - "requires": { - "tslib": "^2.3.1" - } - }, "@babel/code-frame": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz", - "integrity": "sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "requires": { - "@babel/highlight": "^7.24.6", + "@babel/highlight": "^7.24.7", "picocolors": "^1.0.0" } }, @@ -661,51 +653,6 @@ "semver": "^6.3.1" }, "dependencies": { - "@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - } - }, - "@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true - }, - "@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - } - }, - "@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - } - }, "convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -743,37 +690,11 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", - "dev": true, "requires": { "@babel/types": "^7.24.7", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" - }, - "dependencies": { - "@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true - }, - "@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - } - } } }, "@babel/helper-compilation-targets": { @@ -816,111 +737,34 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, "requires": { "@babel/types": "^7.24.7" - }, - "dependencies": { - "@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true - }, - "@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - } - } } }, "@babel/helper-function-name": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, "requires": { "@babel/template": "^7.24.7", "@babel/types": "^7.24.7" - }, - "dependencies": { - "@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true - }, - "@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - } - } } }, "@babel/helper-hoist-variables": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, "requires": { "@babel/types": "^7.24.7" - }, - "dependencies": { - "@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true - }, - "@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - } - } } }, "@babel/helper-module-imports": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.6.tgz", - "integrity": "sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "requires": { - "@babel/types": "^7.24.6" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" } }, "@babel/helper-module-transforms": { @@ -934,47 +778,12 @@ "@babel/helper-simple-access": "^7.24.7", "@babel/helper-split-export-declaration": "^7.24.7", "@babel/helper-validator-identifier": "^7.24.7" - }, - "dependencies": { - "@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dev": true, - "requires": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - } - }, - "@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true - }, - "@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - } - } } }, "@babel/helper-plugin-utils": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", - "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz", + "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==", "dev": true }, "@babel/helper-simple-access": { @@ -985,76 +794,25 @@ "requires": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" - }, - "dependencies": { - "@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true - }, - "@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - } - } } }, "@babel/helper-split-export-declaration": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, "requires": { "@babel/types": "^7.24.7" - }, - "dependencies": { - "@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true - }, - "@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - } - } } }, "@babel/helper-string-parser": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.6.tgz", - "integrity": "sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==" + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", + "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==" }, "@babel/helper-validator-identifier": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz", - "integrity": "sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==" + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==" }, "@babel/helper-validator-option": { "version": "7.24.7", @@ -1070,39 +828,14 @@ "requires": { "@babel/template": "^7.24.7", "@babel/types": "^7.24.7" - }, - "dependencies": { - "@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true - }, - "@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - } - } } }, "@babel/highlight": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.6.tgz", - "integrity": "sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "requires": { - "@babel/helper-validator-identifier": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -1111,8 +844,7 @@ "@babel/parser": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", - "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", - "dev": true + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==" }, "@babel/plugin-syntax-jsx": { "version": "7.24.7", @@ -1132,9 +864,9 @@ } }, "@babel/runtime": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz", - "integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", + "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", "requires": { "regenerator-runtime": "^0.14.0" } @@ -1143,65 +875,16 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", - "dev": true, "requires": { "@babel/code-frame": "^7.24.7", "@babel/parser": "^7.24.7", "@babel/types": "^7.24.7" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - } - }, - "@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true - }, - "@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - } - }, - "@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - } - } } }, "@babel/traverse": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", - "dev": true, "requires": { "@babel/code-frame": "^7.24.7", "@babel/generator": "^7.24.7", @@ -1213,62 +896,15 @@ "@babel/types": "^7.24.7", "debug": "^4.3.1", "globals": "^11.1.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - } - }, - "@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true - }, - "@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - } - }, - "@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - } - } } }, "@babel/types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", - "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", + "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", "requires": { - "@babel/helper-string-parser": "^7.24.6", - "@babel/helper-validator-identifier": "^7.24.6", + "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" } }, @@ -1682,9 +1318,9 @@ } }, "@eslint-community/regexpp": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", - "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true }, "@eslint/eslintrc": { @@ -1772,34 +1408,34 @@ } }, "@floating-ui/core": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.2.tgz", - "integrity": "sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==", + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.4.tgz", + "integrity": "sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA==", "requires": { - "@floating-ui/utils": "^0.2.0" + "@floating-ui/utils": "^0.2.4" } }, "@floating-ui/dom": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz", - "integrity": "sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.7.tgz", + "integrity": "sha512-wmVfPG5o2xnKDU4jx/m4w5qva9FWHcnZ8BvzEe90D/RpwsJaTAVYPEPdQ8sbr/N8zZTAHlZUTQdqg8ZUbzHmng==", "requires": { - "@floating-ui/core": "^1.0.0", - "@floating-ui/utils": "^0.2.0" + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.4" } }, "@floating-ui/react-dom": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.0.tgz", - "integrity": "sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", "requires": { "@floating-ui/dom": "^1.0.0" } }, "@floating-ui/utils": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz", - "integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.4.tgz", + "integrity": "sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==" }, "@fontsource/roboto": { "version": "5.0.13", @@ -1829,6 +1465,11 @@ "resolved": "https://registry.npmjs.org/@functional-abstraction/operator/-/operator-3.0.0.tgz", "integrity": "sha512-Jbf4htiKYk/qa/2Tv0U2KRrfquEPeQ+Bv2CWYYw6kYyJqNlH1hlXi6L8SdQXNs88oyly9Ok994jtwLTwNUFaSg==" }, + "@functional-abstraction/type": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@functional-abstraction/type/-/type-2.0.1.tgz", + "integrity": "sha512-ix2LiRc1ZY//fLF0Q2mQMcNd9I+iHIVbWj62jDkTWvHMqoLKyQdjHoPbqdmJxc5mc6Wka7I6MU8gUYIstMBjYg==" + }, "@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -2343,7 +1984,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "requires": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -2353,26 +1993,22 @@ "@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" }, "@jridgewell/set-array": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" }, "@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -2429,43 +2065,43 @@ } }, "@mui/core-downloads-tracker": { - "version": "5.15.19", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.19.tgz", - "integrity": "sha512-tCHSi/Tomez9ERynFhZRvFO6n9ATyrPs+2N80DMDzp6xDVirbBjEwhPcE+x7Lj+nwYw0SqFkOxyvMP0irnm55w==" + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.0.tgz", + "integrity": "sha512-8SLffXYPRVpcZx5QzxNE8fytTqzp+IuU3deZbQWg/vSaTlDpR5YVrQ4qQtXTi5cRdhOufV5INylmwlKK+//nPw==" }, "@mui/icons-material": { - "version": "5.15.19", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.19.tgz", - "integrity": "sha512-RsEiRxA5azN9b8gI7JRqekkgvxQUlitoBOtZglflb8cUDyP12/cP4gRwhb44Ea1/zwwGGjAj66ZJpGHhKfibNA==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.0.tgz", + "integrity": "sha512-6ISoOhkp9w5gD0PEW9JklrcbyARDkFWNTBdwXZ1Oy5IGlyu9B0zG0hnUIe4H17IaF1Vgj6C8VI+v4tkSdK0veg==", "requires": { "@babel/runtime": "^7.23.9" } }, "@mui/lab": { - "version": "5.0.0-alpha.170", - "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-5.0.0-alpha.170.tgz", - "integrity": "sha512-0bDVECGmrNjd3+bLdcLiwYZ0O4HP5j5WSQm5DV6iA/Z9kr8O6AnvZ1bv9ImQbbX7Gj3pX4o43EKwCutj3EQxQg==", + "version": "5.0.0-alpha.171", + "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-5.0.0-alpha.171.tgz", + "integrity": "sha512-/ZRnx0wB7hWHMsy76AAUJREVHZ7v5kOKwgJKCQrqOcaPNyo3WiwtTqKaM4Pgj+2r7O10IrC6zOniq8kTRqVAlA==", "requires": { "@babel/runtime": "^7.23.9", "@mui/base": "5.0.0-beta.40", - "@mui/system": "^5.15.15", + "@mui/system": "^5.16.0", "@mui/types": "^7.2.14", - "@mui/utils": "^5.15.14", + "@mui/utils": "^5.16.0", "clsx": "^2.1.0", "prop-types": "^15.8.1" } }, "@mui/material": { - "version": "5.15.19", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.19.tgz", - "integrity": "sha512-lp5xQBbcRuxNtjpWU0BWZgIrv2XLUz4RJ0RqFXBdESIsKoGCQZ6P3wwU5ZPuj5TjssNiKv9AlM+vHopRxZhvVQ==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.0.tgz", + "integrity": "sha512-DbR1NckTLpjt9Zut9EGQ70th86HfN0BYQgyYro6aXQrNfjzSwe3BJS1AyBQ5mJ7TdL6YVRqohfukxj9JlqZZUg==", "requires": { "@babel/runtime": "^7.23.9", "@mui/base": "5.0.0-beta.40", - "@mui/core-downloads-tracker": "^5.15.19", - "@mui/system": "^5.15.15", + "@mui/core-downloads-tracker": "^5.16.0", + "@mui/system": "^5.16.0", "@mui/types": "^7.2.14", - "@mui/utils": "^5.15.14", + "@mui/utils": "^5.16.0", "@types/react-transition-group": "^4.4.10", "clsx": "^2.1.0", "csstype": "^3.1.3", @@ -2482,12 +2118,12 @@ } }, "@mui/private-theming": { - "version": "5.15.14", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.14.tgz", - "integrity": "sha512-UH0EiZckOWcxiXLX3Jbb0K7rC8mxTr9L9l6QhOZxYc4r8FHUkefltV9VDGLrzCaWh30SQiJvAEd7djX3XXY6Xw==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.0.tgz", + "integrity": "sha512-sYpubkO1MZOnxNyVOClrPNOTs0MfuRVVnAvCeMaOaXt6GimgQbnUcshYv2pSr6PFj+Mqzdff/FYOBceK8u5QgA==", "requires": { "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.15.14", + "@mui/utils": "^5.16.0", "prop-types": "^15.8.1" } }, @@ -2503,15 +2139,15 @@ } }, "@mui/system": { - "version": "5.15.15", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.15.tgz", - "integrity": "sha512-aulox6N1dnu5PABsfxVGOZffDVmlxPOVgj56HrUnJE8MCSh8lOvvkd47cebIVQQYAjpwieXQXiDPj5pwM40jTQ==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.0.tgz", + "integrity": "sha512-9YbkC2m3+pNumAvubYv+ijLtog6puJ0fJ6rYfzfLCM47pWrw3m+30nXNM8zMgDaKL6vpfWJcCXm+LPaWBpy7sw==", "requires": { "@babel/runtime": "^7.23.9", - "@mui/private-theming": "^5.15.14", + "@mui/private-theming": "^5.16.0", "@mui/styled-engine": "^5.15.14", "@mui/types": "^7.2.14", - "@mui/utils": "^5.15.14", + "@mui/utils": "^5.16.0", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -2523,9 +2159,9 @@ "integrity": "sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==" }, "@mui/utils": { - "version": "5.15.14", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.14.tgz", - "integrity": "sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.0.tgz", + "integrity": "sha512-kLLi5J1xY+mwtUlMb8Ubdxf4qFAA1+U7WPBvjM/qQ4CIwLCohNb0sHo1oYPufjSIH/Z9+dhVxD7dJlfGjd1AVA==", "requires": { "@babel/runtime": "^7.23.9", "@types/prop-types": "^15.7.11", @@ -2541,9 +2177,9 @@ } }, "@mui/x-date-pickers": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-6.20.0.tgz", - "integrity": "sha512-q/x3rNmPYMXnx75+3s9pQb1YDtws9y5bwxpxeB3EW88oCp33eS7bvJpeuoCA1LzW/PpVfIRhi5RCyAvrEeTL7Q==", + "version": "6.20.2", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-6.20.2.tgz", + "integrity": "sha512-x1jLg8R+WhvkmUETRfX2wC+xJreMii78EXKLl6r3G+ggcAZlPyt0myID1Amf6hvJb9CtR7CgUo8BwR+1Vx9Ggw==", "requires": { "@babel/runtime": "^7.23.2", "@mui/base": "^5.0.0-beta.22", @@ -2940,295 +2576,355 @@ "dev": true }, "@smithy/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-p6GlFGBt9K4MYLu72YuJ523NVR4A8oHlC5M2JO6OmQqN8kAc/uh1JqLE+FizTokrSJGg0CSvC+BrsmGzKtsZKA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", "dev": true, + "optional": true, "requires": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@smithy/config-resolver": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.1.tgz", - "integrity": "sha512-hbkYJc20SBDz2qqLzttjI/EqXemtmWk0ooRznLsiXp3066KQRTvuKHa7U4jCZCJq6Dozqvy0R1/vNESC9inPJg==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.4.tgz", + "integrity": "sha512-VwiOk7TwXoE7NlNguV/aPq1hFH72tqkHCw8eWXbr2xHspRyyv9DLpLXhq+Ieje+NwoqXrY0xyQjPXdOE6cGcHA==", "dev": true, + "optional": true, "requires": { - "@smithy/node-config-provider": "^3.1.0", - "@smithy/types": "^3.0.0", + "@smithy/node-config-provider": "^3.1.3", + "@smithy/types": "^3.3.0", "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" } }, "@smithy/core": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.2.0.tgz", - "integrity": "sha512-ygLZSSKgt9bR8HAxR9mK+U5obvAJBr6zlQuhN5soYWx/amjDoQN4dTkydTypgKe6rIbUjTILyLU+W5XFwXr4kg==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.2.4.tgz", + "integrity": "sha512-qdY3LpMOUyLM/gfjjMQZui+UTNS7kBRDWlvyIhVOql5dn2J3isk9qUTBtQ1CbDH8MTugHis1zu3h4rH+Qmmh4g==", "dev": true, + "optional": true, "requires": { - "@smithy/middleware-endpoint": "^3.0.1", - "@smithy/middleware-retry": "^3.0.3", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.1.1", - "@smithy/types": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", + "@smithy/middleware-endpoint": "^3.0.4", + "@smithy/middleware-retry": "^3.0.7", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/protocol-http": "^4.0.3", + "@smithy/smithy-client": "^3.1.5", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" } }, "@smithy/credential-provider-imds": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.1.0.tgz", - "integrity": "sha512-q4A4d38v8pYYmseu/jTS3Z5I3zXlEOe5Obi+EJreVKgSVyWUHOd7/yaVCinC60QG4MRyCs98tcxBH1IMC0bu7Q==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.1.3.tgz", + "integrity": "sha512-U1Yrv6hx/mRK6k8AncuI6jLUx9rn0VVSd9NPEX6pyYFBfkSkChOc/n4zUb8alHUVg83TbI4OdZVo1X0Zfj3ijA==", "dev": true, + "optional": true, "requires": { - "@smithy/node-config-provider": "^3.1.0", - "@smithy/property-provider": "^3.1.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", + "@smithy/node-config-provider": "^3.1.3", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", "tslib": "^2.6.2" } }, "@smithy/fetch-http-handler": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.0.1.tgz", - "integrity": "sha512-uaH74i5BDj+rBwoQaXioKpI0SHBJFtOVwzrCpxZxphOW0ki5jhj7dXvDMYM2IJem8TpdFvS2iC08sjOblfFGFg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.0.tgz", + "integrity": "sha512-vFvDxMrc6sO5Atec8PaISckMcAwsCrRhYxwUylg97bRT2KZoumOF7qk5+6EVUtuM1IG9AJV5aqXnHln9ZdXHpg==", "dev": true, + "optional": true, "requires": { - "@smithy/protocol-http": "^4.0.0", - "@smithy/querystring-builder": "^3.0.0", - "@smithy/types": "^3.0.0", + "@smithy/protocol-http": "^4.0.3", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", "@smithy/util-base64": "^3.0.0", "tslib": "^2.6.2" } }, "@smithy/hash-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.0.tgz", - "integrity": "sha512-84qXstNemP3XS5jcof0el6+bDfjzuvhJPQTEfro3lgtbCtKgzPm3MgiS6ehXVPjeQ5+JS0HqmTz8f/RYfzHVxw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.3.tgz", + "integrity": "sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==", "dev": true, + "optional": true, "requires": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.3.0", "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dev": true, + "optional": true, + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dev": true, + "optional": true, + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } } }, "@smithy/invalid-dependency": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.0.tgz", - "integrity": "sha512-F6wBBaEFgJzj0s4KUlliIGPmqXemwP6EavgvDqYwCH40O5Xr2iMHvS8todmGVZtuJCorBkXsYLyTu4PuizVq5g==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz", + "integrity": "sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==", "dev": true, + "optional": true, "requires": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", "dev": true, + "optional": true, "requires": { "tslib": "^2.6.2" } }, "@smithy/middleware-content-length": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.0.tgz", - "integrity": "sha512-3C4s4d/iGobgCtk2tnWW6+zSTOBg1PRAm2vtWZLdriwTroFbbWNSr3lcyzHdrQHnEXYCC5K52EbpfodaIUY8sg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.3.tgz", + "integrity": "sha512-Dbz2bzexReYIQDWMr+gZhpwBetNXzbhnEMhYKA6urqmojO14CsXjnsoPYO8UL/xxcawn8ZsuVU61ElkLSltIUQ==", "dev": true, + "optional": true, "requires": { - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", + "@smithy/protocol-http": "^4.0.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@smithy/middleware-endpoint": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.0.1.tgz", - "integrity": "sha512-lQ/UOdGD4KM5kLZiAl0q8Qy3dPbynvAXKAdXnYlrA1OpaUwr+neSsVokDZpY6ZVb5Yx8jnus29uv6XWpM9P4SQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.0.4.tgz", + "integrity": "sha512-whUJMEPwl3ANIbXjBXZVdJNgfV2ZU8ayln7xUM47rXL2txuenI7jQ/VFFwCzy5lCmXScjp6zYtptW5Evud8e9g==", "dev": true, + "optional": true, "requires": { - "@smithy/middleware-serde": "^3.0.0", - "@smithy/node-config-provider": "^3.1.0", - "@smithy/shared-ini-file-loader": "^3.1.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/node-config-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.3", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" } }, "@smithy/middleware-retry": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.3.tgz", - "integrity": "sha512-Wve1qzJb83VEU/6q+/I0cQdAkDnuzELC6IvIBwDzUEiGpKqXgX1v10FUuZGbRS6Ov/P+HHthcAoHOJZQvZNAkA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.7.tgz", + "integrity": "sha512-f5q7Y09G+2h5ivkSx5CHvlAT4qRR3jBFEsfXyQ9nFNiWQlr8c48blnu5cmbTQ+p1xmIO14UXzKoF8d7Tm0Gsjw==", "dev": true, + "optional": true, "requires": { - "@smithy/node-config-provider": "^3.1.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/service-error-classification": "^3.0.0", - "@smithy/smithy-client": "^3.1.1", - "@smithy/types": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", + "@smithy/node-config-provider": "^3.1.3", + "@smithy/protocol-http": "^4.0.3", + "@smithy/service-error-classification": "^3.0.3", + "@smithy/smithy-client": "^3.1.5", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", "tslib": "^2.6.2", "uuid": "^9.0.1" } }, "@smithy/middleware-serde": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.0.tgz", - "integrity": "sha512-I1vKG1foI+oPgG9r7IMY1S+xBnmAn1ISqployvqkwHoSb8VPsngHDTOgYGYBonuOKndaWRUGJZrKYYLB+Ane6w==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", + "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", "dev": true, + "optional": true, "requires": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@smithy/middleware-stack": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.0.tgz", - "integrity": "sha512-+H0jmyfAyHRFXm6wunskuNAqtj7yfmwFB6Fp37enytp2q047/Od9xetEaUbluyImOlGnGpaVGaVfjwawSr+i6Q==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", + "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", "dev": true, + "optional": true, "requires": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@smithy/node-config-provider": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.0.tgz", - "integrity": "sha512-ngfB8QItUfTFTfHMvKuc2g1W60V1urIgZHqD1JNFZC2tTWXahqf2XvKXqcBS7yZqR7GqkQQZy11y/lNOUWzq7Q==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.3.tgz", + "integrity": "sha512-rxdpAZczzholz6CYZxtqDu/aKTxATD5DAUDVj7HoEulq+pDSQVWzbg0btZDlxeFfa6bb2b5tUvgdX5+k8jUqcg==", "dev": true, + "optional": true, "requires": { - "@smithy/property-provider": "^3.1.0", - "@smithy/shared-ini-file-loader": "^3.1.0", - "@smithy/types": "^3.0.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@smithy/node-http-handler": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.0.0.tgz", - "integrity": "sha512-3trD4r7NOMygwLbUJo4eodyQuypAWr7uvPnebNJ9a70dQhVn+US8j/lCnvoJS6BXfZeF7PkkkI0DemVJw+n+eQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.1.tgz", + "integrity": "sha512-L71NLyPeP450r2J/mfu1jMc//Z1YnqJt2eSNw7uhiItaONnBLDA68J5jgxq8+MBDsYnFwNAIc7dBG1ImiWBiwg==", "dev": true, + "optional": true, "requires": { - "@smithy/abort-controller": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/querystring-builder": "^3.0.0", - "@smithy/types": "^3.0.0", + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.0.3", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@smithy/property-provider": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.0.tgz", - "integrity": "sha512-Tj3+oVhqdZgemjCiWjFlADfhvLF4C/uKDuKo7/tlEsRQ9+3emCreR2xndj970QSRSsiCEU8hZW3/8JQu+n5w4Q==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", "dev": true, + "optional": true, "requires": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@smithy/protocol-http": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.0.tgz", - "integrity": "sha512-qOQZOEI2XLWRWBO9AgIYuHuqjZ2csyr8/IlgFDHDNuIgLAMRx2Bl8ck5U5D6Vh9DPdoaVpuzwWMa0xcdL4O/AQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.3.tgz", + "integrity": "sha512-x5jmrCWwQlx+Zv4jAtc33ijJ+vqqYN+c/ZkrnpvEe/uDas7AT7A/4Rc2CdfxgWv4WFGmEqODIrrUToPN6DDkGw==", "dev": true, + "optional": true, "requires": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@smithy/querystring-builder": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.0.tgz", - "integrity": "sha512-bW8Fi0NzyfkE0TmQphDXr1AmBDbK01cA4C1Z7ggwMAU5RDz5AAv/KmoRwzQAS0kxXNf/D2ALTEgwK0U2c4LtRg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", "dev": true, + "optional": true, "requires": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.3.0", "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" } }, "@smithy/querystring-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.0.tgz", - "integrity": "sha512-UzHwthk0UEccV4dHzPySnBy34AWw3V9lIqUTxmozQ+wPDAO9csCWMfOLe7V9A2agNYy7xE+Pb0S6K/J23JSzfQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", + "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", "dev": true, + "optional": true, "requires": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@smithy/service-error-classification": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.0.tgz", - "integrity": "sha512-3BsBtOUt2Gsnc3X23ew+r2M71WwtpHfEDGhHYHSDg6q1t8FrWh15jT25DLajFV1H+PpxAJ6gqe9yYeRUsmSdFA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", + "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", "dev": true, + "optional": true, "requires": { - "@smithy/types": "^3.0.0" + "@smithy/types": "^3.3.0" } }, "@smithy/shared-ini-file-loader": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.0.tgz", - "integrity": "sha512-dAM7wSX0NR3qTNyGVN/nwwpEDzfV9T/3AN2eABExWmda5VqZKSsjlINqomO5hjQWGv+IIkoXfs3u2vGSNz8+Rg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.3.tgz", + "integrity": "sha512-Z8Y3+08vgoDgl4HENqNnnzSISAaGrF2RoKupoC47u2wiMp+Z8P/8mDh1CL8+8ujfi2U5naNvopSBmP/BUj8b5w==", "dev": true, + "optional": true, "requires": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@smithy/signature-v4": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-3.0.0.tgz", - "integrity": "sha512-kXFOkNX+BQHe2qnLxpMEaCRGap9J6tUGLzc3A9jdn+nD4JdMwCKTJ+zFwQ20GkY+mAXGatyTw3HcoUlR39HwmA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-3.1.2.tgz", + "integrity": "sha512-3BcPylEsYtD0esM4Hoyml/+s7WP2LFhcM3J2AGdcL2vx9O60TtfpDOL72gjb4lU8NeRPeKAwR77YNyyGvMbuEA==", "dev": true, + "optional": true, "requires": { "@smithy/is-array-buffer": "^3.0.0", - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.3.0", "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", "@smithy/util-uri-escape": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dev": true, + "optional": true, + "requires": { + "tslib": "^2.6.2" + } + } } }, "@smithy/smithy-client": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.1.tgz", - "integrity": "sha512-tj4Ku7MpzZR8cmVuPcSbrLFVxmptWktmJMwST/uIEq4sarabEdF8CbmQdYB7uJ/X51Qq2EYwnRsoS7hdR4B7rA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.5.tgz", + "integrity": "sha512-x9bL9Mx2CT2P1OiUlHM+ZNpbVU6TgT32f9CmTRzqIHA7M4vYrROCWEoC3o4xHNJASoGd4Opos3cXYPgh+/m4Ww==", "dev": true, + "optional": true, "requires": { - "@smithy/middleware-endpoint": "^3.0.1", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-stream": "^3.0.1", + "@smithy/middleware-endpoint": "^3.0.4", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/protocol-http": "^4.0.3", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.0.5", "tslib": "^2.6.2" } }, "@smithy/types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.0.0.tgz", - "integrity": "sha512-VvWuQk2RKFuOr98gFhjca7fkBS+xLLURT8bUjk5XQoV0ZLm7WPwWPPY3/AwzTLuUBDeoKDCthfe1AsTUWaSEhw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dev": true, + "optional": true, "requires": { "tslib": "^2.6.2" } }, "@smithy/url-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.0.tgz", - "integrity": "sha512-2XLazFgUu+YOGHtWihB3FSLAfCUajVfNBXGGYjOaVKjLAuAxx3pSBY3hBgLzIgB17haf59gOG3imKqTy8mcrjw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", + "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", "dev": true, + "optional": true, "requires": { - "@smithy/querystring-parser": "^3.0.0", - "@smithy/types": "^3.0.0", + "@smithy/querystring-parser": "^3.0.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, @@ -3237,10 +2933,34 @@ "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", "dev": true, + "optional": true, "requires": { "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dev": true, + "optional": true, + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dev": true, + "optional": true, + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } } }, "@smithy/util-body-length-browser": { @@ -3248,6 +2968,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", "dev": true, + "optional": true, "requires": { "tslib": "^2.6.2" } @@ -3257,17 +2978,19 @@ "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", "dev": true, + "optional": true, "requires": { "tslib": "^2.6.2" } }, "@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", "dev": true, + "optional": true, "requires": { - "@smithy/is-array-buffer": "^3.0.0", + "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, @@ -3276,46 +2999,50 @@ "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", "dev": true, + "optional": true, "requires": { "tslib": "^2.6.2" } }, "@smithy/util-defaults-mode-browser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.3.tgz", - "integrity": "sha512-3DFON2bvXJAukJe+qFgPV/rorG7ZD3m4gjCXHD1V5z/tgKQp5MCTCLntrd686tX6tj8Uli3lefWXJudNg5WmCA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.7.tgz", + "integrity": "sha512-Q2txLyvQyGfmjsaDbVV7Sg8psefpFcrnlGapDzXGFRPFKRBeEg6OvFK8FljqjeHSaCZ6/UuzQExUPqBR/2qlDA==", "dev": true, + "optional": true, "requires": { - "@smithy/property-provider": "^3.1.0", - "@smithy/smithy-client": "^3.1.1", - "@smithy/types": "^3.0.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.5", + "@smithy/types": "^3.3.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "@smithy/util-defaults-mode-node": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.3.tgz", - "integrity": "sha512-D0b8GJXecT00baoSQ3Iieu3k3mZ7GY8w1zmg8pdogYrGvWJeLcIclqk2gbkG4K0DaBGWrO6v6r20iwIFfDYrmA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.7.tgz", + "integrity": "sha512-F4Qcj1fG6MGi2BSWCslfsMSwllws/WzYONBGtLybyY+halAcXdWhcew+mej8M5SKd5hqPYp4f7b+ABQEaeytgg==", "dev": true, + "optional": true, "requires": { - "@smithy/config-resolver": "^3.0.1", - "@smithy/credential-provider-imds": "^3.1.0", - "@smithy/node-config-provider": "^3.1.0", - "@smithy/property-provider": "^3.1.0", - "@smithy/smithy-client": "^3.1.1", - "@smithy/types": "^3.0.0", + "@smithy/config-resolver": "^3.0.4", + "@smithy/credential-provider-imds": "^3.1.3", + "@smithy/node-config-provider": "^3.1.3", + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.5", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@smithy/util-endpoints": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.1.tgz", - "integrity": "sha512-ZRT0VCOnKlVohfoABMc8lWeQo/JEFuPWctfNRXgTHbyOVssMOLYFUNWukxxiHRGVAhV+n3c0kPW+zUqckjVPEA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.4.tgz", + "integrity": "sha512-ZAtNf+vXAsgzgRutDDiklU09ZzZiiV/nATyqde4Um4priTmasDH+eLpp3tspL0hS2dEootyFMhu1Y6Y+tzpWBQ==", "dev": true, + "optional": true, "requires": { - "@smithy/node-config-provider": "^3.1.0", - "@smithy/types": "^3.0.0", + "@smithy/node-config-provider": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, @@ -3324,45 +3051,72 @@ "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", "dev": true, + "optional": true, "requires": { "tslib": "^2.6.2" } }, "@smithy/util-middleware": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.0.tgz", - "integrity": "sha512-q5ITdOnV2pXHSVDnKWrwgSNTDBAMHLptFE07ua/5Ty5WJ11bvr0vk2a7agu7qRhrCFRQlno5u3CneU5EELK+DQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", + "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", "dev": true, + "optional": true, "requires": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@smithy/util-retry": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.0.tgz", - "integrity": "sha512-nK99bvJiziGv/UOKJlDvFF45F00WgPLKVIGUfAK+mDhzVN2hb/S33uW2Tlhg5PVBoqY7tDVqL0zmu4OxAHgo9g==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", + "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", "dev": true, + "optional": true, "requires": { - "@smithy/service-error-classification": "^3.0.0", - "@smithy/types": "^3.0.0", + "@smithy/service-error-classification": "^3.0.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "@smithy/util-stream": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.0.1.tgz", - "integrity": "sha512-7F7VNNhAsfMRA8I986YdOY5fE0/T1/ZjFF6OLsqkvQVNP3vZ/szYDfGCyphb7ioA09r32K/0qbSFfNFU68aSzA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.0.5.tgz", + "integrity": "sha512-xC3L5PKMAT/Bh8fmHNXP9sdQ4+4aKVUU3EEJ2CF/lLk7R+wtMJM+v/1B4en7jO++Wa5spGzFDBCl0QxgbUc5Ug==", "dev": true, + "optional": true, "requires": { - "@smithy/fetch-http-handler": "^3.0.1", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/types": "^3.0.0", + "@smithy/fetch-http-handler": "^3.2.0", + "@smithy/node-http-handler": "^3.1.1", + "@smithy/types": "^3.3.0", "@smithy/util-base64": "^3.0.0", "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-hex-encoding": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dev": true, + "optional": true, + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dev": true, + "optional": true, + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } } }, "@smithy/util-uri-escape": { @@ -3370,6 +3124,7 @@ "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", "dev": true, + "optional": true, "requires": { "tslib": "^2.6.2" } @@ -3379,9 +3134,33 @@ "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", "dev": true, + "optional": true, "requires": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dev": true, + "optional": true, + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dev": true, + "optional": true, + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } } }, "@szmarczak/http-timer": { @@ -3617,9 +3396,9 @@ } }, "minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -3768,9 +3547,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.19.3", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.3.tgz", - "integrity": "sha512-KOzM7MhcBFlmnlr/fzISFF5vGWVSvN6fTd4T+ExOt08bA/dA5kpSzY52nMsI1KDFmUREpJelPYyuslLRSjjgCg==", + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", "dev": true, "requires": { "@types/node": "*", @@ -3818,9 +3597,9 @@ "dev": true }, "@types/lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ==" + "version": "4.17.6", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.6.tgz", + "integrity": "sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA==" }, "@types/luxon": { "version": "3.4.2", @@ -4252,9 +4031,9 @@ } }, "acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true }, "acorn-jsx": { @@ -4713,7 +4492,8 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", - "dev": true + "dev": true, + "optional": true }, "boxen": { "version": "4.2.0", @@ -4926,15 +4706,16 @@ } }, "glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.3.tgz", + "integrity": "sha512-Q38SGlYRpVtDBPSWEylRyctn7uDeTp4NQERTLiCT1FqA9JXPYWqAVmQU6qh4r/zMM5ehxTcbaO8EjhWnvEhmyg==", "dev": true, "requires": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" } }, @@ -4945,9 +4726,9 @@ "dev": true }, "minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -5212,9 +4993,9 @@ "dev": true }, "string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "requires": { "emoji-regex": "^10.3.0", @@ -5939,9 +5720,9 @@ } }, "dompurify": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.5.tgz", - "integrity": "sha512-FgbqnEPiv5Vdtwt6Mxl7XSylttCC03cqP5ldNT2z+Kj0nLxPHJH4+1Cyf5Jasxhw93Rl4Oo11qRoUV72fmya2Q==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.6.tgz", + "integrity": "sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ==", "optional": true }, "dot-prop": { @@ -5994,6 +5775,11 @@ "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz", "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==" }, + "emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==" + }, "emoji-favicon-cli": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/emoji-favicon-cli/-/emoji-favicon-cli-3.0.1.tgz", @@ -7287,6 +7073,7 @@ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", "dev": true, + "optional": true, "requires": { "strnum": "^1.0.5" } @@ -7520,9 +7307,9 @@ } }, "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", "dev": true, "requires": { "cross-spawn": "^7.0.0", @@ -7836,8 +7623,7 @@ "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, "globalthis": { "version": "1.0.4", @@ -8206,9 +7992,9 @@ } }, "minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -8412,11 +8198,11 @@ } }, "is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", "requires": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" } }, "is-data-view": { @@ -8804,9 +8590,9 @@ } }, "jackspeak": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.2.5.tgz", - "integrity": "sha512-a1hopwtr4NawFIrSmFgufzrN1Qy2BAfMJ0yScJBs/olJhTcctCy3YIDx4hTY2DOTJD1pUMTly80kmlYZxjZr5w==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.1.tgz", + "integrity": "sha512-U23pQPDnmYybVkYjObcuYMk43VRlMLLqLI+RdZy8s8WV8WsxO9SnqSroKaluuvcNOdCAlauKszDwd+umbot5Mg==", "dev": true, "requires": { "@isaacs/cliui": "^8.0.2", @@ -8814,9 +8600,9 @@ } }, "jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", "dev": true }, "jju": { @@ -8854,8 +8640,7 @@ "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" }, "json-buffer": { "version": "3.0.1", @@ -9041,16 +8826,16 @@ } }, "listr2": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.1.tgz", - "integrity": "sha512-irTfvpib/rNiD637xeevjO2l3Z5loZmuaRi0L0YE5LfijwVY96oyVn0DFD3o/teAok7nfobMG1THvvcHh/BP6g==", + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.3.tgz", + "integrity": "sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==", "dev": true, "requires": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.0.0", - "rfdc": "^1.3.1", + "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" }, "dependencies": { @@ -9073,9 +8858,9 @@ "dev": true }, "string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "requires": { "emoji-regex": "^10.3.0", @@ -9299,9 +9084,9 @@ } }, "string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "requires": { "emoji-regex": "^10.3.0", @@ -9355,9 +9140,9 @@ "dev": true }, "lru-cache": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==" + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.3.1.tgz", + "integrity": "sha512-9/8QXrtbGeMB6LxwQd4x1tIMnsmUxMvIH/qWGsccz6bt9Uln3S+sgAaqfQNhbGA8ufzs2fHuP/yqapGgP9Hh2g==" }, "lz-string": { "version": "1.5.0", @@ -10811,9 +10596,9 @@ } }, "nan": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", - "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==" + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", + "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==" }, "natural-compare": { "version": "1.4.0", @@ -11217,15 +11002,16 @@ } }, "glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.3.tgz", + "integrity": "sha512-Q38SGlYRpVtDBPSWEylRyctn7uDeTp4NQERTLiCT1FqA9JXPYWqAVmQU6qh4r/zMM5ehxTcbaO8EjhWnvEhmyg==", "dev": true, "requires": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" } }, @@ -11254,9 +11040,9 @@ "dev": true }, "minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -11293,9 +11079,9 @@ "dev": true }, "rimraf": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", - "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", + "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", "dev": true, "requires": { "glob": "^10.3.7" @@ -11444,9 +11230,9 @@ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" }, "object-is": { "version": "1.1.6", @@ -11728,6 +11514,12 @@ "semver": "^7.3.7" } }, + "package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true + }, "pacote": { "version": "15.2.0", "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.2.0.tgz", @@ -11787,9 +11579,9 @@ } }, "parse-github-url": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz", - "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.3.tgz", + "integrity": "sha512-tfalY5/4SqGaV/GIGzWyHnFjlpTPTNpENR9Ea2lLldSJ8EWXMsvacWucqY3m3I4YPtas15IxTLQVQ5NSYXPrww==", "dev": true }, "parse-json": { @@ -12021,22 +11813,23 @@ } }, "glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.3.tgz", + "integrity": "sha512-Q38SGlYRpVtDBPSWEylRyctn7uDeTp4NQERTLiCT1FqA9JXPYWqAVmQU6qh4r/zMM5ehxTcbaO8EjhWnvEhmyg==", "dev": true, "requires": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" } }, "minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -12499,15 +12292,16 @@ } }, "glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.3.tgz", + "integrity": "sha512-Q38SGlYRpVtDBPSWEylRyctn7uDeTp4NQERTLiCT1FqA9JXPYWqAVmQU6qh4r/zMM5ehxTcbaO8EjhWnvEhmyg==", "dev": true, "requires": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" } }, @@ -12533,9 +12327,9 @@ "dev": true }, "minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -13604,7 +13398,8 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "dev": true + "dev": true, + "optional": true }, "stylis": { "version": "4.2.0", @@ -14275,7 +14070,8 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "dev": true + "dev": true, + "optional": true }, "uuid-random": { "version": "1.3.2", @@ -15232,9 +15028,9 @@ "dev": true }, "typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true } } @@ -15287,9 +15083,9 @@ } }, "yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", "dev": true }, "zod": { diff --git a/package.json b/package.json index 41e3d1f0e..6d9fe1f9b 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@functional-abstraction/operator": "^3.0.0", + "@functional-abstraction/type": "^2.0.1", "@heap-data-structure/pairing-heap": "^4.0.0", "@iterable-iterator/cardinality": "^4.0.0", "@iterable-iterator/chain": "^2.0.0", @@ -96,6 +97,7 @@ "debounce": "^1.2.1", "downshift": "^7.2.1", "email-addresses": "^5.0.0", + "emittery": "^0.13.1", "escape-string-regexp": "^5.0.0", "express": "^4.18.2", "fast-diff": "^1.3.0", diff --git a/server/api/ics/index.ts b/server/api/ics/index.ts index c95ff77f8..2c2c40d0b 100644 --- a/server/api/ics/index.ts +++ b/server/api/ics/index.ts @@ -85,8 +85,8 @@ const response = async (token, IPAddress, query, res) => { await Consultations.find(selector, { sort: {lastModifiedAt: -1}, - }).forEachAsync(({_id, ...fields}) => { - const {begin, end, title, description, isCancelled, uri} = event( + }).forEachAsync(async ({_id, ...fields}) => { + const {begin, end, title, description, isCancelled, uri} = await event( _id, fields, ); diff --git a/server/main.ts b/server/main.ts index 1efb7aa75..c9966e9ec 100644 --- a/server/main.ts +++ b/server/main.ts @@ -2,14 +2,12 @@ import './polyfill'; import {WebApp} from 'meteor/webapp'; -import {Accounts} from 'meteor/accounts-base'; // DECLARE ALL ENABLED API ENDPOINTS // eslint-disable-next-line import/no-unassigned-import import '../imports/api/endpoint/_register/enabled'; import atStartup from '../imports/app/atStartup'; -import isTest from '../imports/app/isTest'; import scheduleAllMigrations from '../imports/migrations/scheduleAll'; // DECLARE ALL ENABLED PUBLICATIONS @@ -23,11 +21,6 @@ import healthcheck from './api/healthcheck/index'; WebApp.connectHandlers.use('/api/ics', ics); WebApp.connectHandlers.use('/api/healthcheck', healthcheck); -if (isTest()) { - // @ts-expect-error Missing from type definitions. - Accounts.removeDefaultRateLimit(); -} - atStartup(async () => { await scheduleAllMigrations(); }); diff --git a/test/app/client/patient/appointments.app-tests.ts b/test/app/client/patient/appointments.app-tests.ts index a3ca04d2e..c5a55bc0c 100644 --- a/test/app/client/patient/appointments.app-tests.ts +++ b/test/app/client/patient/appointments.app-tests.ts @@ -55,7 +55,7 @@ const scheduleAppointmentForPatient = async ( console.debug('Click on Schedule'); await user.click(await findByRole('button', {name: 'Schedule'})); console.debug('Check heading'); - await findByRole('heading', {name: /^\/consultation\//}); + await findByRole('heading', {name: /^\/consultation\//}, {timeout: 10_000}); console.debug('Check button'); await findByRole('button', {name: 'Cancel'}); await historyBack(); diff --git a/types/meteor/diff-sequence.d.ts b/types/meteor/diff-sequence.d.ts new file mode 100644 index 000000000..72a6b8aac --- /dev/null +++ b/types/meteor/diff-sequence.d.ts @@ -0,0 +1,45 @@ +declare module 'meteor/diff-sequence' { + import {type Mongo} from 'meteor/mongo'; + import {type Document} from 'mongodb'; + + type DiffOptions = { + projectionFn?: (document: T) => Partial; + }; + + namespace DiffSequence { + function diffQueryChanges( + ordered: true, + old_results: T[], + new_results: T[], + observer: Mongo.ObserveChangesCallbacks, + options?: DiffOptions | undefined, + ): void; + + function diffQueryChanges( + ordered: false, + old_results: Map, + new_results: Map, + observer: Mongo.ObserveChangesCallbacks, + options?: DiffOptions | undefined, + ): void; + + function diffQueryUnorderedChanges( + old_results: Map, + new_results: Map, + observer: Mongo.ObserveChangesCallbacks, + options?: DiffOptions | undefined, + ): void; + + function diffQueryOrderedChanges( + old_results: T[], + new_results: T[], + observer: Mongo.ObserveChangesCallbacks, + options?: DiffOptions | undefined, + ): void; + + function applyChanges( + document: T, + changes: Partial, + ): void; + } +} diff --git a/types/meteor/minimongo.d.ts b/types/meteor/minimongo.d.ts new file mode 100644 index 000000000..5af0cfcc6 --- /dev/null +++ b/types/meteor/minimongo.d.ts @@ -0,0 +1,10 @@ +declare module 'meteor/minimongo' { + import {type Mongo} from 'meteor/mongo'; + import {type Document} from 'mongodb'; + + namespace LocalCollection { + function _observeCallbacksAreOrdered( + callbacks: Mongo.ObserveChangesCallbacks, + ): boolean; + } +} diff --git a/types/meteor/mongo.d.ts b/types/meteor/mongo.d.ts new file mode 100644 index 000000000..38a88f5b6 --- /dev/null +++ b/types/meteor/mongo.d.ts @@ -0,0 +1,19 @@ +import {Mongo} from 'meteor/mongo'; + +export {MongoInternals} from 'meteor/mongo'; + +declare module 'meteor/mongo' { + namespace Mongo { + // eslint-disable-next-line @typescript-eslint/consistent-type-definitions + interface CursorDescription { + collectionName: string; + selector: Selector; + options: Options; + } + // eslint-disable-next-line @typescript-eslint/consistent-type-definitions + interface Cursor { + _cursorDescription: CursorDescription; + _getCollectionName(): string; + } + } +}