commit 2094278819b6290d17b3e84e27782ba287e429b0 parent f49d24ae6e99b0a879d99855aa1b4eb183157610 Author: Christian Blättler <blatc2@bfh.ch> Date: Tue, 19 Dec 2023 17:56:48 +0100 Merge branch 'master' into feature/tokens Diffstat:
190 files changed, 9390 insertions(+), 6995 deletions(-)
diff --git a/API_CHANGES.md b/API_CHANGES.md @@ -0,0 +1,36 @@ +# API Changes + +This files contains all the API changes for the current release: + +## wallet-core + +- AcceptManualWithdrawalResult.exchangePaytoUris is deprecated +- WithdrawalExchangeAccountDetails.transferAmount is now optional (if convertion applies) +- added WithdrawalExchangeAccountDetails.currencySpecification about the transferAmount currency +- 2023-12-05 dold: added WithdrawalExchangeAccountDetails.{status,conversionError} to inform the client + about errors with a particular conversion account instead of failing the whole withdrawal(-info) request. +- 2023-12-06 dold: added the exchangeBaseUrl to PreparePeerPushCreditResponse, allowing the UI + to check the exchange status for the peer push credit. +- 2023-12-06 dold: added a new getExchangeEntryForUri request, which allows the client to + get information about an existing exchange entry with DD48 semantics. + The older call "getExchangeDetailedInfo" also computes loads of information + for fee comparison and we should eventually rename it to something more appropriate + (like getExchangeFeeDetailsForUri). +- 2023-12-06 dold: Deprecate the tosStatus in the withdrawal details response. + This field does not conform to DD48 semantics and the client should + request the ToS status separately via a getExchangeEntryForUri request. +- 2023-12-07 dold: Add the prepareWithdrawExchange request for withdrawals + via a taler://withdraw-exchange URI. +- 2023-12-11 dold: Add exchangeBaseUrl to the checkPeerPushDebit response. +- 2023-12-11 dold: Add scopeInfo to exchange entry list items. +- BREAK 2023-12-12 dold: Remove forceUpdate and masterPub arguments from addExchange + request. This request has previously been overloaded both to update an + exchange entry as well as to add it. + To update the entry, updateExchangeEntry should be used instead. +- 2023-12-12 dold: the getExchangeTos request not accepts an additional + acceptLanguage field in the request. The response now contains an optional + contentLanguage field that is returned if the exchange reports it. +- 2023-12-12 2:0:1 dold: The checkPeerPushDebit now returns a maximum + expiration date based on the expiry of selected coins. +- 2023-12-13 3:0:2 dold: getVersion now returns the supported API version + ranges for all bank APIs separately. diff --git a/Makefile b/Makefile @@ -145,6 +145,7 @@ install: $(MAKE) -C packages/merchant-backoffice-ui install-nodeps $(MAKE) -C packages/aml-backoffice-ui install-nodeps + .PHONY: install-tools # Install taler-wallet-cli, anastasis-cli and taler-harness install-tools: @@ -153,3 +154,4 @@ install-tools: $(MAKE) -C packages/taler-wallet-cli install-nodeps $(MAKE) -C packages/anastasis-cli install-nodeps $(MAKE) -C packages/taler-harness install-nodeps + diff --git a/package.json b/package.json @@ -12,9 +12,9 @@ "@babel/core": "7.13.16", "@linaria/esbuild": "^3.0.0-beta.15", "@linaria/shaker": "^3.0.0-beta.15", - "esbuild": "^0.17.7", - "prettier": "^2.8.8", - "typedoc": "^0.25.1", - "typescript": "^5.2.2" + "esbuild": "^0.19.9", + "prettier": "^3.1.1", + "typedoc": "^0.25.4", + "typescript": "^5.3.3" } } diff --git a/packages/aml-backoffice-ui/package.json b/packages/aml-backoffice-ui/package.json @@ -54,14 +54,14 @@ "@types/mocha": "^10.0.1", "autoprefixer": "^10.4.14", "chai": "^4.3.6", - "esbuild": "^0.17.7", + "esbuild": "^0.19.9", "eslint-config-preact": "^1.2.0", "mocha": "^9.2.0", "po2json": "^0.4.5", "postcss": "^8.4.23", "postcss-cli": "^10.1.0", "tailwindcss": "^3.3.2", - "typescript": "5.2.2" + "typescript": "5.3.3" }, "pogen": { "domain": "aml-backoffice" diff --git a/packages/aml-backoffice-ui/src/Dashboard.tsx b/packages/aml-backoffice-ui/src/Dashboard.tsx @@ -165,7 +165,7 @@ export function ExchangeAmlFrame({ </div> <Footer - testingUrl={localStorage.getItem("exchange-base-url") ?? undefined} + testingUrlKey="exchange-base-url" GIT_HASH={GIT_HASH} VERSION={VERSION} /> diff --git a/packages/anastasis-cli/package.json b/packages/anastasis-cli/package.json @@ -32,13 +32,13 @@ ], "devDependencies": { "@types/node": "^18.11.17", - "prettier": "^2.8.8", - "typedoc": "^0.25.1", - "typescript": "^5.2.2" + "prettier": "^3.1.1", + "typedoc": "^0.25.4", + "typescript": "^5.3.3" }, "dependencies": { "@gnu-taler/anastasis-core": "workspace:*", "@gnu-taler/taler-util": "workspace:*", - "tslib": "^2.5.3" + "tslib": "^2.6.2" } } diff --git a/packages/anastasis-core/package.json b/packages/anastasis-core/package.json @@ -17,13 +17,13 @@ "license": "AGPL-3-or-later", "type": "module", "devDependencies": { - "ava": "^4.3.3", - "typescript": "^5.2.2" + "ava": "^6.0.1", + "typescript": "^5.3.3" }, "dependencies": { "@gnu-taler/taler-util": "workspace:*", - "fflate": "^0.7.4", - "tslib": "^2.5.3" + "fflate": "^0.8.1", + "tslib": "^2.6.2" }, "ava": { "files": [ diff --git a/packages/anastasis-core/src/index.ts b/packages/anastasis-core/src/index.ts @@ -1657,7 +1657,7 @@ export function mergeDiscoveryAggregate( newPolicies: PolicyMetaInfo[], oldAgg: AggregatedPolicyMetaInfo[], ): AggregatedPolicyMetaInfo[] { - const aggregatedPolicies: AggregatedPolicyMetaInfo[] = [...oldAgg] ?? []; + const aggregatedPolicies: AggregatedPolicyMetaInfo[] = [...oldAgg]; const polHashToIndex: Record<string, number> = {}; for (const pol of newPolicies) { const oldIndex = polHashToIndex[pol.policy_hash]; diff --git a/packages/anastasis-webui/package.json b/packages/anastasis-webui/package.json @@ -46,6 +46,6 @@ "chai": "^4.3.6", "mocha": "^9.2.0", "sass": "1.56.1", - "typescript": "^5.2.2" + "typescript": "^5.3.3" } } diff --git a/packages/challenger-ui/package.json b/packages/challenger-ui/package.json @@ -36,7 +36,7 @@ "@tailwindcss/forms": "^0.5.3", "@tailwindcss/typography": "^0.5.9", "autoprefixer": "^10.4.14", - "esbuild": "^0.17.7", + "esbuild": "^0.19.9", "po2json": "^0.4.5", "postcss": "^8.4.23", "postcss-cli": "^10.1.0", diff --git a/packages/demobank-ui/package.json b/packages/demobank-ui/package.json @@ -48,25 +48,25 @@ "@gnu-taler/pogen": "^0.0.5", "@tailwindcss/forms": "^0.5.3", "@tailwindcss/typography": "^0.5.9", - "autoprefixer": "^10.4.14", "@types/chai": "^4.3.0", "@types/history": "^4.7.8", "@types/mocha": "^10.0.1", "@types/node": "^18.11.17", "@typescript-eslint/eslint-plugin": "^5.41.0", "@typescript-eslint/parser": "^5.41.0", + "autoprefixer": "^10.4.14", "bulma": "^0.9.4", "bulma-checkbox": "^1.1.1", "bulma-radio": "^1.1.1", "chai": "^4.3.6", - "esbuild": "^0.17.7", + "esbuild": "^0.19.9", "eslint-config-preact": "^1.2.0", "mocha": "^9.2.0", "po2json": "^0.4.5", "preact-render-to-string": "^5.2.6", "sass": "1.56.1", "tailwindcss": "^3.3.2", - "typescript": "5.2.2" + "typescript": "5.3.3" }, "pogen": { "domain": "bank" diff --git a/packages/demobank-ui/src/Routing.tsx b/packages/demobank-ui/src/Routing.tsx @@ -38,12 +38,13 @@ import { WireTransfer } from "./pages/WireTransfer.js"; import { AccountPage } from "./pages/AccountPage/index.js"; import { useSettingsContext } from "./context/settings.js"; import { useBankCoreApiContext } from "./context/config.js"; +import { DownloadStats } from "./pages/DownloadStats.js"; export function Routing(): VNode { const history = createHashHistory(); const backend = useBackendState(); const settings = useSettingsContext(); - const {config} = useBankCoreApiContext(); + const { config } = useBankCoreApiContext(); const { i18n } = useTranslationContext(); if (backend.state.status === "loggedOut") { @@ -119,6 +120,14 @@ export function Routing(): VNode { path="/public-accounts" component={() => <PublicHistoriesPage />} /> + <Route + path="/download-stats" + component={() => <DownloadStats + onCancel={() => { + route("/account") + }} + />} + /> <Route path="/new-account" @@ -193,6 +202,20 @@ export function Routing(): VNode { /> <Route + path="/delete-my-account" + component={() => ( + <RemoveAccount + account={username} + onUpdateSuccess={() => { + route("/") + }} + onCancel={() => { + route("/account") + }} + /> + )} + /> + <Route path="/my-profile" component={() => ( <ShowAccountDetails diff --git a/packages/demobank-ui/src/components/Cashouts/index.ts b/packages/demobank-ui/src/components/Cashouts/index.ts @@ -14,14 +14,11 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { ErrorLoading, HttpError, utils } from "@gnu-taler/web-util/browser"; -import { Loading } from "@gnu-taler/web-util/browser"; -// import { compose, StateViewMap } from "../../utils/index.js"; -// import { wxApi } from "../../wxApi.js"; +import { Loading, utils } from "@gnu-taler/web-util/browser"; import { AbsoluteTime, AmountJson, TalerCoreBankErrorsByMethod, TalerCorebankApi, TalerError } from "@gnu-taler/taler-util"; +import { ErrorLoadingWithDebug } from "../ErrorLoadingWithDebug.js"; import { useComponentState } from "./state.js"; -import { FailedView, LoadingUriView, ReadyView } from "./views.js"; -import { h } from "preact"; +import { FailedView, ReadyView } from "./views.js"; export interface Props { account: string; @@ -67,9 +64,7 @@ export interface Transaction { const viewMapping: utils.StateViewMap<State> = { loading: Loading, - "loading-error": ({error}) => { - return h(ErrorLoading, {error, showDetail:true}); - }, + "loading-error": ErrorLoadingWithDebug, "failed": FailedView, ready: ReadyView, }; diff --git a/packages/demobank-ui/src/components/Cashouts/views.tsx b/packages/demobank-ui/src/components/Cashouts/views.tsx @@ -15,22 +15,14 @@ */ import { Amounts, TalerError, assertUnreachable } from "@gnu-taler/taler-util"; -import { Attention, ErrorLoading, Loading, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { Attention, Loading, useTranslationContext } from "@gnu-taler/web-util/browser"; import { format } from "date-fns"; -import { Fragment, h, VNode } from "preact"; +import { Fragment, VNode, h } from "preact"; +import { useConversionInfo } from "../../hooks/circuit.js"; import { RenderAmount } from "../../pages/PaytoWireTransferForm.js"; +import { ErrorLoadingWithDebug } from "../ErrorLoadingWithDebug.js"; import { State } from "./index.js"; -import { useConversionInfo } from "../../hooks/circuit.js"; -export function LoadingUriView({ error }: State.LoadingUriError): VNode { - const { i18n } = useTranslationContext(); - - return ( - <div> - <i18n.Translate>Could not load</i18n.Translate> - </div> - ); -} export function FailedView({ error }: State.Failed) { const { i18n } = useTranslationContext(); switch (error.case) { @@ -57,7 +49,7 @@ export function ReadyView({ cashouts, onSelected }: State.Ready): VNode { return <Loading /> } if (resp instanceof TalerError) { - return <ErrorLoading error={resp} /> + return <ErrorLoadingWithDebug error={resp} /> } if (!cashouts.length) return <div /> const txByDate = cashouts.reduce((prev, cur) => { @@ -105,9 +97,9 @@ export function ReadyView({ cashouts, onSelected }: State.Ready): VNode { return (<tr key={idx} class="border-b border-gray-200 hover:bg-gray-200 last:border-none"> <td onClick={(e) => { - e.preventDefault(); - onSelected(item.id); - }} class="relative py-2 pl-2 pr-2 text-sm "> + e.preventDefault(); + onSelected(item.id); + }} class="relative py-2 pl-2 pr-2 text-sm "> <div class="font-medium text-gray-900">{creationTime}</div> {/* <dl class="font-normal sm:hidden"> <dt class="sr-only sm:hidden"><i18n.Translate>Amount</i18n.Translate></dt> @@ -132,26 +124,26 @@ export function ReadyView({ cashouts, onSelected }: State.Ready): VNode { </dl> */} </td> <td onClick={(e) => { - e.preventDefault(); - onSelected(item.id); - }}class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 cursor-pointer">{confirmationTime}</td> + e.preventDefault(); + onSelected(item.id); + }} class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 cursor-pointer">{confirmationTime}</td> <td onClick={(e) => { - e.preventDefault(); - onSelected(item.id); - }}class="hidden sm:table-cell px-3 py-3.5 text-sm text-red-600 cursor-pointer"><RenderAmount value={Amounts.parseOrThrow(item.amount_debit)} spec={resp.body.regional_currency_specification} /></td> + e.preventDefault(); + onSelected(item.id); + }} class="hidden sm:table-cell px-3 py-3.5 text-sm text-red-600 cursor-pointer"><RenderAmount value={Amounts.parseOrThrow(item.amount_debit)} spec={resp.body.regional_currency_specification} /></td> <td onClick={(e) => { - e.preventDefault(); - onSelected(item.id); - }}class="hidden sm:table-cell px-3 py-3.5 text-sm text-green-600 cursor-pointer"><RenderAmount value={Amounts.parseOrThrow(item.amount_credit)} spec={resp.body.fiat_currency_specification} /></td> + e.preventDefault(); + onSelected(item.id); + }} class="hidden sm:table-cell px-3 py-3.5 text-sm text-green-600 cursor-pointer"><RenderAmount value={Amounts.parseOrThrow(item.amount_credit)} spec={resp.body.fiat_currency_specification} /></td> - <td onClick={(e) => { - e.preventDefault(); - onSelected(item.id); - }}class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 cursor-pointer">{item.status}</td> <td onClick={(e) => { - e.preventDefault(); - onSelected(item.id); - }} class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 break-all min-w-md"> + e.preventDefault(); + onSelected(item.id); + }} class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 cursor-pointer">{item.status}</td> + <td onClick={(e) => { + e.preventDefault(); + onSelected(item.id); + }} class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 break-all min-w-md"> {item.subject} </td> </tr>) diff --git a/packages/demobank-ui/src/components/EmptyComponentExample/views.tsx b/packages/demobank-ui/src/components/EmptyComponentExample/views.tsx @@ -23,7 +23,6 @@ export function LoadingUriView({ error }: State.LoadingUriError): VNode { return ( <div> - <i18n.Translate>Could not load</i18n.Translate> </div> ); } diff --git a/packages/demobank-ui/src/components/ErrorLoadingWithDebug.tsx b/packages/demobank-ui/src/components/ErrorLoadingWithDebug.tsx @@ -0,0 +1,9 @@ +import { TalerError } from "@gnu-taler/taler-util"; +import { ErrorLoading } from "@gnu-taler/web-util/browser"; +import { VNode, h } from "preact"; +import { usePreferences } from "../hooks/preferences.js"; + +export function ErrorLoadingWithDebug({ error }: { error: TalerError }): VNode { + const [pref] = usePreferences(); + return <ErrorLoading error={error} showDetail={pref.showDebugInfo} /> +} diff --git a/packages/demobank-ui/src/components/Transactions/index.ts b/packages/demobank-ui/src/components/Transactions/index.ts @@ -14,10 +14,11 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { Loading, utils } from "@gnu-taler/web-util/browser"; import { AbsoluteTime, AmountJson, TalerError } from "@gnu-taler/taler-util"; +import { Loading, utils } from "@gnu-taler/web-util/browser"; +import { ErrorLoadingWithDebug } from "../ErrorLoadingWithDebug.js"; import { useComponentState } from "./state.js"; -import { LoadingUriView, ReadyView } from "./views.js"; +import { ReadyView } from "./views.js"; export interface Props { account: string; @@ -58,7 +59,7 @@ export interface Transaction { const viewMapping: utils.StateViewMap<State> = { loading: Loading, - "loading-error": LoadingUriView, + "loading-error": ErrorLoadingWithDebug, ready: ReadyView, }; diff --git a/packages/demobank-ui/src/components/Transactions/views.tsx b/packages/demobank-ui/src/components/Transactions/views.tsx @@ -17,23 +17,14 @@ import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { format } from "date-fns"; import { Fragment, h, VNode } from "preact"; -import { doAutoFocus, RenderAmount } from "../../pages/PaytoWireTransferForm.js"; -import { State } from "./index.js"; import { useBankCoreApiContext } from "../../context/config.js"; +import { RenderAmount } from "../../pages/PaytoWireTransferForm.js"; +import { State } from "./index.js"; -export function LoadingUriView({ error }: State.LoadingUriError): VNode { - const { i18n } = useTranslationContext(); - - return ( - <div> - <i18n.Translate>Could not load</i18n.Translate> - </div> - ); -} export function ReadyView({ transactions, onNext, onPrev }: State.Ready): VNode { const { i18n } = useTranslationContext(); - const {config} = useBankCoreApiContext(); + const { config } = useBankCoreApiContext(); if (!transactions.length) return <div /> const txByDate = transactions.reduce((prev, cur) => { const d = cur.when.t_ms === "never" @@ -80,7 +71,7 @@ export function ReadyView({ transactions, onNext, onPrev }: State.Ready): VNode <dd class="mt-1 truncate text-gray-700"> {item.negative ? i18n.str`sent` : i18n.str`received`} {item.amount ? ( <span data-negative={item.negative ? "true" : "false"} class="data-[negative=false]:text-green-600 data-[negative=true]:text-red-600"> - <RenderAmount value={item.amount} spec={config.currency_specification}/> + <RenderAmount value={item.amount} spec={config.currency_specification} /> </span> ) : ( <span style={{ color: "grey" }}><{i18n.str`invalid value`}></span> @@ -101,7 +92,7 @@ export function ReadyView({ transactions, onNext, onPrev }: State.Ready): VNode </td> <td data-negative={item.negative ? "true" : "false"} class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 "> - {item.amount ? (<RenderAmount value={item.amount} negative={item.negative} withColor spec={config.currency_specification}/> + {item.amount ? (<RenderAmount value={item.amount} negative={item.negative} withColor spec={config.currency_specification} /> ) : ( <span style={{ color: "grey" }}><{i18n.str`invalid value`}></span> )} diff --git a/packages/demobank-ui/src/components/app.tsx b/packages/demobank-ui/src/components/app.tsx @@ -79,7 +79,7 @@ export default App; function getInitialBackendBaseURL(backendFromSettings: string | undefined): string { const overrideUrl = typeof localStorage !== "undefined" - ? localStorage.getItem("bank-base-url") + ? localStorage.getItem("corebank-api-base-url") : undefined; let result: string; diff --git a/packages/demobank-ui/src/context/config.ts b/packages/demobank-ui/src/context/config.ts @@ -15,10 +15,9 @@ */ import { TalerCorebankApi, TalerCoreBankHttpClient, TalerError } from "@gnu-taler/taler-util"; -import { BrowserHttpLib, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { BrowserHttpLib, ErrorLoading, useTranslationContext } from "@gnu-taler/web-util/browser"; import { ComponentChildren, createContext, FunctionComponent, h, VNode } from "preact"; import { useContext, useEffect, useState } from "preact/hooks"; -import { ErrorLoading } from "@gnu-taler/web-util/browser"; /** * diff --git a/packages/demobank-ui/src/hooks/access.ts b/packages/demobank-ui/src/hooks/access.ts @@ -14,8 +14,8 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { AccessToken, TalerCoreBankResultByMethod, TalerHttpError } from "@gnu-taler/taler-util"; -import { useState } from "preact/hooks"; +import { AccessToken, TalerBankIntegrationResultByMethod, TalerCoreBankResultByMethod, TalerHttpError, WithdrawalOperationStatus } from "@gnu-taler/taler-util"; +import { useEffect, useState } from "preact/hooks"; import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils.js"; import { useBackendState } from "./backend.js"; @@ -56,18 +56,17 @@ export function useAccountDetails(account: string) { return undefined; } -// FIXME: should poll export function useWithdrawalDetails(wid: string) { - // const { state: credentials } = useBackendState(); const { api } = useBankCoreApiContext(); + const [latestStatus, setLatestStatus] = useState<WithdrawalOperationStatus>() - async function fetcher([wid]: [string]) { - return await api.getWithdrawalById(wid) + async function fetcher([wid, old_state]: [string, WithdrawalOperationStatus | undefined]) { + return await api.getWithdrawalById(wid, old_state === undefined ? undefined : { old_state, timeoutMs: 15000 }) } const { data, error } = useSWR<TalerCoreBankResultByMethod<"getWithdrawalById">, TalerHttpError>( - [wid, "getWithdrawalById"], fetcher, { - refreshInterval: 1000, + [wid, latestStatus, "getWithdrawalById"], fetcher, { + refreshInterval: 3000, refreshWhenHidden: false, revalidateOnFocus: false, revalidateOnReconnect: false, @@ -78,6 +77,14 @@ export function useWithdrawalDetails(wid: string) { keepPreviousData: true, }); + const currentStatus = data !== undefined && data.type === "ok" ? data.body.status : undefined; + + useEffect(() => { + if (currentStatus !== undefined && currentStatus !== latestStatus) { + setLatestStatus(currentStatus) + } + }, [currentStatus]) + if (data) return data; if (error) return error; return undefined; @@ -110,12 +117,12 @@ export function useTransactionDetails(account: string, tid: number) { return undefined; } -export function usePublicAccounts(initial?: number) { +export function usePublicAccounts(filterAccount: string | undefined, initial?: number) { const [offset, setOffset] = useState<number | undefined>(initial); const { api } = useBankCoreApiContext(); - async function fetcher([txid]: [number | undefined]) { - return await api.getPublicAccounts({ + async function fetcher([account, txid]: [string | undefined, number | undefined]) { + return await api.getPublicAccounts({ account }, { limit: MAX_RESULT_SIZE, offset: txid ? String(txid) : undefined, order: "asc" @@ -123,7 +130,7 @@ export function usePublicAccounts(initial?: number) { } const { data, error } = useSWR<TalerCoreBankResultByMethod<"getPublicAccounts">, TalerHttpError>( - [offset, "getPublicAccounts"], fetcher, { + [filterAccount, offset, "getPublicAccounts"], fetcher, { refreshInterval: 0, refreshWhenHidden: false, revalidateOnFocus: false, diff --git a/packages/demobank-ui/src/hooks/circuit.ts b/packages/demobank-ui/src/hooks/circuit.ts @@ -194,7 +194,7 @@ export function useOnePendingCashouts(account: string) { } const { data, error } = useSWR<OperationOk<CashoutWithId | undefined> | TalerCoreBankErrorsByMethod<"getAccountCashouts"> | TalerCoreBankErrorsByMethod<"getCashoutById">, TalerHttpError>( - !config.allow_conversion ? undefined : [account, token, "getAccountCashouts"], fetcher, { + !config.allow_conversion ? undefined : [account, token, "useOnePendingCashouts"], fetcher, { refreshInterval: 0, refreshWhenHidden: false, revalidateOnFocus: false, @@ -229,13 +229,12 @@ export function useCashouts(account: string) { return { ...r.body, id: c.cashout_id } }) })) - const cashouts = all.filter(notUndefined) return { type: "ok" as const, body: { cashouts } } } const { data, error } = useSWR<OperationOk<{ cashouts: CashoutWithId[] }> | TalerCoreBankErrorsByMethod<"getAccountCashouts">, TalerHttpError>( - !config.allow_conversion ? undefined : [account, token, "getAccountCashouts"], fetcher, { + !config.allow_conversion ? undefined : [account, token, "useCashouts"], fetcher, { refreshInterval: 0, refreshWhenHidden: false, revalidateOnFocus: false, diff --git a/packages/demobank-ui/src/pages/AccountPage/index.ts b/packages/demobank-ui/src/pages/AccountPage/index.ts @@ -15,9 +15,8 @@ */ import { AbsoluteTime, AmountJson, TalerCorebankApi, TalerError } from "@gnu-taler/taler-util"; -import { utils } from "@gnu-taler/web-util/browser"; -import { ErrorLoading } from "@gnu-taler/web-util/browser"; -import { Loading } from "@gnu-taler/web-util/browser"; +import { Loading, utils } from "@gnu-taler/web-util/browser"; +import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js"; import { LoginForm } from "../LoginForm.js"; import { useComponentState } from "./state.js"; import { InvalidIbanView, ReadyView } from "./views.js"; @@ -76,7 +75,7 @@ const viewMapping: utils.StateViewMap<State> = { loading: Loading, "login": LoginForm, "invalid-iban": InvalidIbanView, - "loading-error": ErrorLoading, + "loading-error": ErrorLoadingWithDebug, ready: ReadyView, }; diff --git a/packages/demobank-ui/src/pages/BankFrame.tsx b/packages/demobank-ui/src/pages/BankFrame.tsx @@ -47,8 +47,10 @@ export function BankFrame({ if (error) { const desc = (error instanceof Error ? error.stack : String(error)) as TranslatedString if (error instanceof Error) { + console.log("Internal error, please report", error) notifyException(i18n.str`Internal error, please report.`, error) } else { + console.log("Internal error, please report", error) notifyError(i18n.str`Internal error, please report.`, String(error) as TranslatedString) } resetError() @@ -117,10 +119,7 @@ export function BankFrame({ </main> <Footer - testingUrl={ - (typeof localStorage !== "undefined") && localStorage.getItem("bank-base-url") ? - localStorage.getItem("bank-base-url") ?? undefined : - undefined} + testingUrlKey="corebank-api-base-url" GIT_HASH={GIT_HASH} VERSION={VERSION} /> @@ -130,17 +129,6 @@ export function BankFrame({ ); } -function MaybeShowDebugInfo({ info }: { info: any }): VNode { - const [settings] = usePreferences() - if (settings.showDebugInfo) { - return <pre class="whitespace-break-spaces "> - {info} - </pre> - } - return <Fragment /> -} - - function WelcomeAccount({ account: accountName }: { account: string }): VNode { const { i18n } = useTranslationContext(); return <a href="#/my-profile" class="underline underline-offset-2"> diff --git a/packages/demobank-ui/src/pages/DownloadStats.tsx b/packages/demobank-ui/src/pages/DownloadStats.tsx @@ -0,0 +1,396 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import { AccessToken, AmountString, Logger, TalerCoreBankHttpClient, TalerCorebankApi, TalerError } from "@gnu-taler/taler-util"; +import { Attention, LocalNotificationBanner, useLocalNotification, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { Fragment, VNode, h } from "preact"; +import { useState } from "preact/hooks"; +import { useBankCoreApiContext } from "../context/config.js"; +import { useBackendState } from "../hooks/backend.js"; +import { getTimeframesForDate } from "./admin/AdminHome.js"; + +const logger = new Logger("PublicHistoriesPage"); + +interface Props { + onCancel: () => void; +} + +type Options = { + dayMetric: boolean; + hourMetric: boolean; + monthMetric: boolean; + yearMetric: boolean; + compareWithPrevious: boolean; + endOnFirstFail: boolean; + includeHeader: boolean; +} + +/** + * Show histories of public accounts. + */ +export function DownloadStats({ onCancel }: Props): VNode { + const { i18n } = useTranslationContext(); + + const { state: credentials } = useBackendState(); + const creds = credentials.status !== "loggedIn" || !credentials.isUserAdministrator ? undefined : credentials + const { api } = useBankCoreApiContext(); + + const [options, setOptions] = useState<Options>({ + compareWithPrevious: true, + dayMetric: true, + endOnFirstFail: false, + hourMetric: true, + includeHeader: true, + monthMetric: true, + yearMetric: true, + }) + const [lastStep, setLastStep] = useState<{ step: number, total: number }>() + const [downloaded, setDownloaded] = useState<string>() + const referenceDates = [new Date()] + const [notification, notify, handleError] = useLocalNotification() + + if (!creds) { + return <div>only admin can download stats</div> + } + + return ( + <div> + + <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg"> + <LocalNotificationBanner notification={notification} /> + + <div class="px-4 sm:px-0"> + <h2 class="text-base font-semibold leading-7 text-gray-900"> + <i18n.Translate>Download bank stats</i18n.Translate> + </h2> + </div> + + + <form + class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2" + autoCapitalize="none" + autoCorrect="off" + onSubmit={e => { + e.preventDefault() + }} + > + <div class="px-4 py-6 sm:p-8"> + <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6"> + <div class="sm:col-span-5"> + <div class="flex items-center justify-between"> + <span class="flex flex-grow flex-col"> + <span class="text-sm text-black font-medium leading-6 " id="availability-label"> + <i18n.Translate>Include hour metric</i18n.Translate> + </span> + </span> + <button type="button" data-enabled={options.hourMetric} class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" role="switch" aria-checked="false" aria-labelledby="availability-label" aria-describedby="availability-description" + + onClick={() => { setOptions({ ...options, hourMetric: !options.hourMetric }) }}> + <span aria-hidden="true" data-enabled={options.hourMetric} class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"></span> + </button> + </div> + </div> + <div class="sm:col-span-5"> + <div class="flex items-center justify-between"> + <span class="flex flex-grow flex-col"> + <span class="text-sm text-black font-medium leading-6 " id="availability-label"> + <i18n.Translate>Include day metric</i18n.Translate> + </span> + </span> + <button type="button" data-enabled={!!options.dayMetric} class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" role="switch" aria-checked="false" aria-labelledby="availability-label" aria-describedby="availability-description" + + onClick={() => { setOptions({ ...options, dayMetric: !options.dayMetric }) }}> + <span aria-hidden="true" data-enabled={options.dayMetric} class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"></span> + </button> + </div> + </div> + <div class="sm:col-span-5"> + <div class="flex items-center justify-between"> + <span class="flex flex-grow flex-col"> + <span class="text-sm text-black font-medium leading-6 " id="availability-label"> + <i18n.Translate>Include month metric</i18n.Translate> + </span> + </span> + <button type="button" data-enabled={!!options.monthMetric} class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" role="switch" aria-checked="false" aria-labelledby="availability-label" aria-describedby="availability-description" + + onClick={() => { setOptions({ ...options, monthMetric: !options.monthMetric }) }}> + <span aria-hidden="true" data-enabled={options.monthMetric} class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"></span> + </button> + </div> + </div> + <div class="sm:col-span-5"> + <div class="flex items-center justify-between"> + <span class="flex flex-grow flex-col"> + <span class="text-sm text-black font-medium leading-6 " id="availability-label"> + <i18n.Translate>Include year metric</i18n.Translate> + </span> + </span> + <button type="button" data-enabled={!!options.yearMetric} class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" role="switch" aria-checked="false" aria-labelledby="availability-label" aria-describedby="availability-description" + + onClick={() => { setOptions({ ...options, yearMetric: !options.yearMetric }) }}> + <span aria-hidden="true" data-enabled={options.yearMetric} class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"></span> + </button> + </div> + </div> + <div class="sm:col-span-5"> + <div class="flex items-center justify-between"> + <span class="flex flex-grow flex-col"> + <span class="text-sm text-black font-medium leading-6 " id="availability-label"> + <i18n.Translate>Include table header</i18n.Translate> + </span> + </span> + <button type="button" data-enabled={!!options.includeHeader} class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" role="switch" aria-checked="false" aria-labelledby="availability-label" aria-describedby="availability-description" + + onClick={() => { setOptions({ ...options, includeHeader: !options.includeHeader }) }}> + <span aria-hidden="true" data-enabled={options.includeHeader} class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"></span> + </button> + </div> + </div> + <div class="sm:col-span-5"> + <div class="flex items-center justify-between"> + <span class="flex flex-grow flex-col"> + <span class="text-sm text-black font-medium leading-6 " id="availability-label"> + <i18n.Translate>Add previous metric for compare</i18n.Translate> + </span> + </span> + <button type="button" data-enabled={!!options.compareWithPrevious} class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" role="switch" aria-checked="false" aria-labelledby="availability-label" aria-describedby="availability-description" + + onClick={() => { setOptions({ ...options, compareWithPrevious: !options.compareWithPrevious }) }}> + <span aria-hidden="true" data-enabled={options.compareWithPrevious} class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"></span> + </button> + </div> + </div> + <div class="sm:col-span-5"> + <div class="flex items-center justify-between"> + <span class="flex flex-grow flex-col"> + <span class="text-sm text-black font-medium leading-6 " id="availability-label"> + <i18n.Translate>Fail on first error</i18n.Translate> + </span> + </span> + <button type="button" data-enabled={!!options.endOnFirstFail} class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" role="switch" aria-checked="false" aria-labelledby="availability-label" aria-describedby="availability-description" + + onClick={() => { setOptions({ ...options, endOnFirstFail: !options.endOnFirstFail }) }}> + <span aria-hidden="true" data-enabled={options.endOnFirstFail} class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"></span> + </button> + </div> + </div> + </div> + </div> + + + + <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8"> + <button type="button" class="text-sm font-semibold leading-6 text-gray-900" + onClick={onCancel} + > + <i18n.Translate>Cancel</i18n.Translate> + </button> + <button type="submit" + class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" + disabled={lastStep !== undefined} + onClick={async () => { + setDownloaded(undefined) + await handleError(async () => { + const csv = await fetchAllStatus(api, creds.token, options, referenceDates, (step, total) => { + setLastStep({ step, total }) + }) + setDownloaded(csv) + }) + setLastStep(undefined) + }} + > + <i18n.Translate>Download</i18n.Translate> + </button> + </div> + </form> + + </div> + {!lastStep || lastStep.step === lastStep.total ? <div class="h-5 mb-5"/> : <div> + <div class="relative mb-5 h-5 rounded-full bg-gray-200"> + <div class="h-full animate-pulse rounded-full bg-blue-500" style={{ + width: `${Math.round((((lastStep.step / lastStep.total))* 100) )}%` + }}> + <span class="absolute inset-0 flex items-center justify-center text-xs font-semibold text-white"> + <i18n.Translate>downloading... {Math.round((((lastStep.step / lastStep.total))* 100) )}</i18n.Translate> + </span> + </div> + </div> + </div>} + {!downloaded ? <div class="h-5 mb-5"/> : + <a href={"data:text/plain;charset=utf-8," + encodeURIComponent(downloaded)} download={"bank-stats.csv"}> + <Attention title={i18n.str`Download completed`}> + <i18n.Translate>click here to save the file in your computer</i18n.Translate> + </Attention> + </a> + } + </div> + ); +} + + +async function fetchAllStatus(api: TalerCoreBankHttpClient, token: AccessToken, options: Options, references: Date[], progres: (current: number, total: number) => void): Promise<string> { + const allMetrics: TalerCorebankApi.MonitorTimeframeParam[] = []; + if (options.hourMetric) { + allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.hour) + } + if (options.dayMetric) { + allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.day) + } + if (options.monthMetric) { + allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.month) + } + if (options.yearMetric) { + allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.year) + } + + /** + * conver request into frames + */ + const allFrames = allMetrics.flatMap(timeframe => references.map(reference => ({ + reference, + timeframe, + moment: getTimeframesForDate(reference, timeframe) + })) + ) + const total = allFrames.length + + /** + * call API for info + */ + const allInfo = await allFrames.reduce(async (prev, frame, index) => { + const accumulatedMap = await prev + progres(index, total) + // await delay() + const previous = options.compareWithPrevious ? (await api.getMonitor(token, { + timeframe: frame.timeframe, + which: frame.moment.previous + })) : undefined + + if (previous && previous.type === "fail" && options.endOnFirstFail) { + throw TalerError.fromUncheckedDetail(previous.detail) + } + + const current = await api.getMonitor(token, { + timeframe: frame.timeframe, + which: frame.moment.current + }) + + if (current.type === "fail" && options.endOnFirstFail) { + throw TalerError.fromUncheckedDetail(current.detail) + } + + const metricName = TalerCorebankApi.MonitorTimeframeParam[allMetrics[index]] + accumulatedMap[metricName] = { + reference: frame.reference, + current: current.type !== "ok" ? undefined : current.body, + previous: !previous || previous.type !== "ok" ? undefined : previous.body, + } + return accumulatedMap + }, Promise.resolve({} as Record<string, Data>)) + progres(total, total) + + /** + * conver into table format + * + */ + const table: Array<string[]> = []; + if (options.includeHeader) { + table.push(["date", + "metric", + "reference", + "talerInCount", + "talerInVolume", + "talerOutCount", + "talerOutVolume", + "cashinCount", + "cashinFiatVolume", + "cashinRegionalVolume", + "cashoutCount", + "cashoutFiatVolume", + "cashoutRegionalVolume",]) + } + Object.entries(allInfo).forEach(([name, data]) => { + if (data.current) { + const row: TableRow = { + date: data.reference.getTime(), + metric: name, + reference: "current", + ...dataToRow(data.current) + } + table.push((Object.values(row) as string[])) + } + + if (data.previous) { + const row: TableRow = { + date: data.reference.getTime(), + metric: name, + reference: "previous", + ...dataToRow(data.previous) + } + table.push((Object.values(row) as string[])) + } + }) + + const csv = table.reduce((acc, row) => { + return acc + row.join(",") + "\n" + }, "") + + return csv +} + +type JustData = Omit<Omit<Omit<TableRow, "metric">, "date">, "reference"> +function dataToRow(info: TalerCorebankApi.MonitorResponse): JustData { + return { + talerInCount: info.talerInCount, + talerInVolume: info.talerInVolume, + talerOutCount: info.talerOutCount, + talerOutVolume: info.talerOutVolume, + cashinCount: info.type === "no-conversions" ? undefined : info.cashinCount, + cashinFiatVolume: info.type === "no-conversions" ? undefined : info.cashinFiatVolume, + cashinRegionalVolume: info.type === "no-conversions" ? undefined : info.cashinRegionalVolume, + cashoutCount: info.type === "no-conversions" ? undefined : info.cashoutCount, + cashoutFiatVolume: info.type === "no-conversions" ? undefined : info.cashoutFiatVolume, + cashoutRegionalVolume: info.type === "no-conversions" ? undefined : info.cashoutRegionalVolume, + } +} + +type Data = { + reference: Date, + previous: TalerCorebankApi.MonitorResponse | undefined; + current: TalerCorebankApi.MonitorResponse | undefined; +} +type TableRow = { + date: number, + metric: string, + reference: "current" | "previous", + cashinCount?: number; + cashinRegionalVolume?: AmountString; + cashinFiatVolume?: AmountString; + cashoutCount?: number; + cashoutRegionalVolume?: AmountString; + cashoutFiatVolume?: AmountString; + talerInCount: number; + talerInVolume: AmountString; + talerOutCount: number; + talerOutVolume: AmountString; +} +async function delay() { + return new Promise(res => { + setTimeout(( )=> { + res(null) + }, 500) + }) +} +\ No newline at end of file diff --git a/packages/demobank-ui/src/pages/LoginForm.tsx b/packages/demobank-ui/src/pages/LoginForm.tsx @@ -28,31 +28,22 @@ import { assertUnreachable } from "./WithdrawalOperationPage.js"; /** * Collect and submit login data. */ -export function LoginForm({ reason, onRegister }: { reason?: "not-found" | "forbidden", onRegister?: () => void }): VNode { +export function LoginForm({ currentUser, fixedUser, onRegister }: { fixedUser?: boolean, currentUser?: string, onRegister?: () => void }): VNode { const backend = useBackendState(); - const currentUser = backend.state.status !== "loggedOut" ? backend.state.username : undefined - const [username, setUsername] = useState<string | undefined>(currentUser); + + const sessionUser = backend.state.status !== "loggedOut" ? backend.state.username : undefined + const [username, setUsername] = useState<string | undefined>(currentUser ?? sessionUser); const [password, setPassword] = useState<string | undefined>(); const { i18n } = useTranslationContext(); const { api } = useBankCoreApiContext(); const [notification, notify, handleError] = useLocalNotification() const {config} = useBankCoreApiContext(); - - /** - * Register form may be shown in the initialization step. - * If no register handler then this is invoke - * to show a session expired or unauthorized - */ - const isLogginAgain = !onRegister - + const ref = useRef<HTMLInputElement>(null); useEffect(function focusInput() { - if (isLogginAgain && backend.state.status !== "expired") { - backend.expired() - window.location.reload() - } ref.current?.focus(); }, []); + const [busy, setBusy] = useState<Record<string, undefined>>() const errors = undefinedIfEmpty({ @@ -128,7 +119,7 @@ export function LoginForm({ reason, onRegister }: { reason?: "not-found" | "forb id="username" class="block w-full disabled:bg-gray-200 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" value={username ?? ""} - disabled={isLogginAgain} + disabled={fixedUser} enterkeyhint="next" placeholder="identification" autocomplete="username" @@ -170,7 +161,7 @@ export function LoginForm({ reason, onRegister }: { reason?: "not-found" | "forb </div> </div> - {isLogginAgain ? <div class="flex justify-between"> + {backend.state.status !== "loggedOut" ? <div class="flex justify-between"> <button type="submit" class="rounded-md bg-white-600 px-3 py-1.5 text-sm font-semibold leading-6 text-black shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-600" onClick={(e) => { @@ -189,7 +180,7 @@ export function LoginForm({ reason, onRegister }: { reason?: "not-found" | "forb doLogin() }} > - <i18n.Translate>Renew session</i18n.Translate> + <i18n.Translate>Check</i18n.Translate> </button> </div> : <div> <button type="submit" diff --git a/packages/demobank-ui/src/pages/OperationState/index.ts b/packages/demobank-ui/src/pages/OperationState/index.ts @@ -14,10 +14,9 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { AbsoluteTime, AmountJson, TalerCoreBankErrorsByMethod, TalerError, TalerErrorDetail, TranslatedString, WithdrawUriResult } from "@gnu-taler/taler-util"; -import { utils } from "@gnu-taler/web-util/browser"; -import { ErrorLoading } from "@gnu-taler/web-util/browser"; -import { Loading } from "@gnu-taler/web-util/browser"; +import { AbsoluteTime, AmountJson, TalerCoreBankErrorsByMethod, TalerError, WithdrawUriResult } from "@gnu-taler/taler-util"; +import { Loading, utils } from "@gnu-taler/web-util/browser"; +import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js"; import { useComponentState } from "./state.js"; import { AbortedView, ConfirmedView, FailedView, InvalidPaytoView, InvalidReserveView, InvalidWithdrawalView, NeedConfirmationView, ReadyView } from "./views.js"; @@ -83,8 +82,9 @@ export namespace State { } export interface NeedConfirmation { status: "need-confirmation", - onAbort: () => Promise<TalerCoreBankErrorsByMethod<"abortWithdrawalById"> | undefined>; - onConfirm: () => Promise<TalerCoreBankErrorsByMethod<"confirmWithdrawalById"> | undefined>; + account: string, + onAbort: undefined | (() => Promise<TalerCoreBankErrorsByMethod<"abortWithdrawalById"> | undefined>); + onConfirm: undefined | (() => Promise<TalerCoreBankErrorsByMethod<"confirmWithdrawalById"> | undefined>); error: undefined; busy: boolean, } @@ -118,7 +118,7 @@ const viewMapping: utils.StateViewMap<State> = { "need-confirmation": NeedConfirmationView, "aborted": AbortedView, "confirmed": ConfirmedView, - "loading-error": ErrorLoading, + "loading-error": ErrorLoadingWithDebug, ready: ReadyView, }; diff --git a/packages/demobank-ui/src/pages/OperationState/state.ts b/packages/demobank-ui/src/pages/OperationState/state.ts @@ -74,7 +74,8 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive const wid = withdrawalOperationId async function doAbort() { - const resp = await api.abortWithdrawalById(wid); + if (!creds) return; + const resp = await api.abortWithdrawalById(creds, wid); if (resp.type === "ok") { updateSettings("currentWithdrawalOperationId", undefined) onClose(); @@ -84,8 +85,9 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive } async function doConfirm(): Promise<TalerCoreBankErrorsByMethod<"confirmWithdrawalById"> | undefined> { + if (!creds) return; setBusy({}) - const resp = await api.confirmWithdrawalById(wid); + const resp = await api.confirmWithdrawalById(creds, wid); setBusy(undefined) if (resp.type === "ok") { mutate(() => true)//clean withdrawal state @@ -132,6 +134,7 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive if (result.type === "fail") { switch (result.case) { + case "invalid-id": case "not-found": { return { status: "aborted", @@ -142,23 +145,12 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive }, } } - case "invalid-id": { - return { - status: "aborted", - error: undefined, - onClose: async () => { - updateSettings("currentWithdrawalOperationId", undefined) - onClose() - }, - } - - } default: assertUnreachable(result) } } const { body: data } = result; - if (data.aborted) { + if (data.status === "aborted") { return { status: "aborted", error: undefined, @@ -169,7 +161,7 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive } } - if (data.confirmation_done) { + if (data.status === "confirmed") { if (!settings.showWithdrawalSuccess) { updateSettings("currentWithdrawalOperationId", undefined) onClose() @@ -184,12 +176,15 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive } } - if (!data.selection_done) { + if (data.status === "pending") { return { status: "ready", error: undefined, uri: parsedUri, - onClose: doAbort, + onClose: !creds ? (async () => { + onClose(); + return undefined + }) : doAbort, } } @@ -216,9 +211,10 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive return { status: "need-confirmation", error: undefined, - onAbort: doAbort, + account: data.username, + onAbort: !creds ? undefined : doAbort, busy: !!busy, - onConfirm: doConfirm + onConfirm: !creds ? undefined : doConfirm } } diff --git a/packages/demobank-ui/src/pages/OperationState/views.tsx b/packages/demobank-ui/src/pages/OperationState/views.tsx @@ -15,18 +15,15 @@ */ import { TranslatedString, stringifyWithdrawUri } from "@gnu-taler/taler-util"; -import { notifyInfo, useLocalNotification, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { Attention, LocalNotificationBanner, ShowInputErrorLabel, notifyInfo, useLocalNotification, useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useEffect, useMemo, useState } from "preact/hooks"; import { QR } from "../../components/QR.js"; -import { ShowInputErrorLabel } from "@gnu-taler/web-util/browser"; import { usePreferences } from "../../hooks/preferences.js"; import { undefinedIfEmpty } from "../../utils.js"; -import { State } from "./index.js"; -import { LocalNotificationBanner } from "@gnu-taler/web-util/browser"; -import { ErrorLoading } from "@gnu-taler/web-util/browser"; -import { Attention } from "@gnu-taler/web-util/browser"; +import { ShouldBeSameUser } from "../WithdrawalConfirmationQuestion.js"; import { assertUnreachable } from "../WithdrawalOperationPage.js"; +import { State } from "./index.js"; export function InvalidPaytoView({ payto, onClose }: State.InvalidPayto) { return ( @@ -44,7 +41,7 @@ export function InvalidReserveView({ reserve, onClose }: State.InvalidReserve) { ); } -export function NeedConfirmationView({ error, onAbort: doAbort, onConfirm: doConfirm, busy }: State.NeedConfirmation) { +export function NeedConfirmationView({ error, onAbort: doAbort, onConfirm: doConfirm, busy, account }: State.NeedConfirmation) { const { i18n } = useTranslationContext() const [settings] = usePreferences() const [notification, notify, errorHandler] = useLocalNotification() @@ -69,6 +66,7 @@ export function NeedConfirmationView({ error, onAbort: doAbort, onConfirm: doCon async function onCancel() { errorHandler(async () => { + if (!doAbort) return; const resp = await doAbort() if (!resp) return; switch (resp.case) { @@ -97,6 +95,7 @@ export function NeedConfirmationView({ error, onAbort: doAbort, onConfirm: doCon async function onConfirm() { errorHandler(async () => { + if (!doConfirm) return; const hasError = await doConfirm() if (!hasError) { if (!settings.showWithdrawalSuccess) { @@ -148,128 +147,65 @@ export function NeedConfirmationView({ error, onAbort: doAbort, onConfirm: doCon <i18n.Translate>Confirm the withdrawal operation</i18n.Translate> </h3> <div class="mt-3 text-sm leading-6"> + <ShouldBeSameUser username={account}> + <form + class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2" + autoCapitalize="none" + autoCorrect="off" + onSubmit={e => { + e.preventDefault() + }} + > + <div class="px-4 py-6 sm:p-8"> + <label for="withdraw-amount">{i18n.str`What is`} + <em> + {captchaNumbers.a} + {captchaNumbers.b} + </em> + ? + </label> + <div class="mt-2"> + <div class="relative rounded-md shadow-sm"> + <input + type="text" + // class="block w-full rounded-md border-0 py-1.5 pl-16 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + aria-describedby="answer" + autoFocus + class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + value={captchaAnswer ?? ""} + required - <form - class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2" - autoCapitalize="none" - autoCorrect="off" - onSubmit={e => { - e.preventDefault() - }} - > - <div class="px-4 py-6 sm:p-8"> - <label for="withdraw-amount">{i18n.str`What is`} - <em> - {captchaNumbers.a} + {captchaNumbers.b} - </em> - ? - </label> - <div class="mt-2"> - <div class="relative rounded-md shadow-sm"> - <input - type="text" - // class="block w-full rounded-md border-0 py-1.5 pl-16 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" - aria-describedby="answer" - autoFocus - class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" - value={captchaAnswer ?? ""} - required - - name="answer" - id="answer" - autocomplete="off" - onChange={(e): void => { - setCaptchaAnswer(e.currentTarget.value) - }} - /> + name="answer" + id="answer" + autocomplete="off" + onChange={(e): void => { + setCaptchaAnswer(e.currentTarget.value) + }} + /> + </div> + <ShowInputErrorLabel message={errors?.answer} isDirty={captchaAnswer !== undefined} /> </div> - <ShowInputErrorLabel message={errors?.answer} isDirty={captchaAnswer !== undefined} /> </div> - </div> - <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8"> - <button type="button" class="text-sm font-semibold leading-6 text-gray-900" - onClick={(e) => { - e.preventDefault() - onCancel() - }} - > - <i18n.Translate>Cancel</i18n.Translate></button> - <button type="submit" - class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" - disabled={!!errors} - onClick={(e) => { - e.preventDefault() - onConfirm() - }} - > - <i18n.Translate>Transfer</i18n.Translate> - </button> - </div> - - </form> - </div> - <div class="px-4 mt-4 "> - {/* <div class="w-full"> - <div class="px-4 sm:px-0 text-sm"> - <p><i18n.Translate>Wire transfer details</i18n.Translate></p> - </div> - <div class="mt-6 border-t border-gray-100"> - <dl class="divide-y divide-gray-100"> - {((): VNode => { - switch (details.account.targetType) { - case "iban": { - const p = details.account as PaytoUriIBAN - const name = p.params["receiver-name"] - return <Fragment> - <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> - <dt class="text-sm font-medium leading-6 text-gray-900">Exchange account</dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{p.iban}</dd> - </div> - {name && - <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> - <dt class="text-sm font-medium leading-6 text-gray-900">Exchange name</dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{p.params["receiver-name"]}</dd> - </div> - } - </Fragment> - } - case "x-taler-bank": { - const p = details.account as PaytoUriTalerBank - const name = p.params["receiver-name"] - return <Fragment> - <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> - <dt class="text-sm font-medium leading-6 text-gray-900">Exchange account</dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{p.account}</dd> - </div> - {name && - <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> - <dt class="text-sm font-medium leading-6 text-gray-900">Exchange name</dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{p.params["receiver-name"]}</dd> - </div> - } - </Fragment> - } - default: - return <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> - <dt class="text-sm font-medium leading-6 text-gray-900">Exchange account</dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">{details.account.targetPath}</dd> - </div> - - } - })()} - <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> - <dt class="text-sm font-medium leading-6 text-gray-900">Withdrawal identification</dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0 break-words">{details.reserve}</dd> - </div> - <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0"> - <dt class="text-sm font-medium leading-6 text-gray-900">Amount</dt> - <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">To be added</dd> - // {/* Amounts.stringifyValue(details.amount) + <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8"> + <button type="button" class="text-sm font-semibold leading-6 text-gray-900" + onClick={(e) => { + e.preventDefault() + onCancel() + }} + > + <i18n.Translate>Cancel</i18n.Translate></button> + <button type="submit" + class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" + disabled={!!errors} + onClick={(e) => { + e.preventDefault() + onConfirm() + }} + > + <i18n.Translate>Transfer</i18n.Translate> + </button> </div> - </dl> - </div> - </div> */} - + </form> + </ShouldBeSameUser> </div> </div> </div> diff --git a/packages/demobank-ui/src/pages/ProfileNavigation.tsx b/packages/demobank-ui/src/pages/ProfileNavigation.tsx @@ -2,10 +2,13 @@ import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useBankCoreApiContext } from "../context/config.js"; import { assertUnreachable } from "./WithdrawalOperationPage.js"; +import { useBackendState } from "../hooks/backend.js"; -export function ProfileNavigation({ current, noCashout }: { noCashout?: boolean, current: "details" | "credentials" | "cashouts" }): VNode { +export function ProfileNavigation({ current }: { current: "details" | "delete" | "credentials" | "cashouts" }): VNode { const { i18n } = useTranslationContext() const { config } = useBankCoreApiContext() + const { state: credentials } = useBackendState(); + const nonAdminUser = credentials.status !== "loggedIn" ? false : !credentials.isUserAdministrator return <div> <div class="sm:hidden"> <label for="tabs" class="sr-only"><i18n.Translate>Select a section</i18n.Translate></label> @@ -16,6 +19,10 @@ export function ProfileNavigation({ current, noCashout }: { noCashout?: boolean, window.location.href = "#/my-profile"; return; } + case "delete": { + window.location.href = "#/delete-my-account"; + return; + } case "credentials": { window.location.href = "#/my-password"; return; @@ -28,6 +35,9 @@ export function ProfileNavigation({ current, noCashout }: { noCashout?: boolean, } }}> <option value="details" selected={current == "details"}><i18n.Translate>Details</i18n.Translate></option> + {!config.allow_deletions ? undefined : + <option value="delete" selected={current == "delete"}><i18n.Translate>Delete</i18n.Translate></option> + } <option value="credentials" selected={current == "credentials"}><i18n.Translate>Credentials</i18n.Translate></option> {config.allow_conversion ? <option value="cashouts" selected={current == "cashouts"}><i18n.Translate>Cashouts</i18n.Translate></option> @@ -40,11 +50,17 @@ export function ProfileNavigation({ current, noCashout }: { noCashout?: boolean, <span><i18n.Translate>Details</i18n.Translate></span> <span aria-hidden="true" data-selected={current == "details"} class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"></span> </a> + {!config.allow_deletions ? undefined : + <a href="#/delete-my-account" data-selected={current == "delete"} aria-current="page" class=" text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"> + <span><i18n.Translate>Delete</i18n.Translate></span> + <span aria-hidden="true" data-selected={current == "delete"} class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"></span> + </a> + } <a href="#/my-password" data-selected={current == "credentials"} aria-current="page" class=" text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"> <span><i18n.Translate>Credentials</i18n.Translate></span> <span aria-hidden="true" data-selected={current == "credentials"} class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"></span> </a> - {config.allow_conversion && !noCashout ? + {config.allow_conversion && nonAdminUser ? <a href="#/my-cashouts" data-selected={current == "cashouts"} class="rounded-r-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"> <span>Cashouts</span> <span aria-hidden="true" data-selected={current == "cashouts"} class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"></span> diff --git a/packages/demobank-ui/src/pages/PublicHistoriesPage.tsx b/packages/demobank-ui/src/pages/PublicHistoriesPage.tsx @@ -32,9 +32,10 @@ interface Props { } export function PublicHistoriesPage({ }: Props): VNode { const { i18n } = useTranslationContext(); - const result = usePublicAccounts(); + //TODO: implemented filter by account name + const result = usePublicAccounts(undefined); const firstAccount = result && !(result instanceof TalerError) && result.data.public_accounts.length > 0 - ? result.data.public_accounts[0].account_name + ? result.data.public_accounts[0].username : undefined; const [showAccount, setShowAccount] = useState(firstAccount); @@ -53,8 +54,8 @@ export function PublicHistoriesPage({ }: Props): VNode { // Ask story of all the public accounts. for (const account of data.public_accounts) { - logger.trace("Asking transactions for", account.account_name); - const isSelected = account.account_name == showAccount; + logger.trace("Asking transactions for", account.username); + const isSelected = account.username == showAccount; accountsBar.push( <li class={ @@ -66,13 +67,13 @@ export function PublicHistoriesPage({ }: Props): VNode { <a href="#" class="pure-menu-link" - onClick={() => setShowAccount(account.account_name)} + onClick={() => setShowAccount(account.username)} > - {account.account_name} + {account.username} </a> </li>, ); - txs[account.account_name] = <Transactions account={account.account_name} />; + txs[account.username] = <Transactions account={account.username} />; } return ( diff --git a/packages/demobank-ui/src/pages/QrCodeSection.tsx b/packages/demobank-ui/src/pages/QrCodeSection.tsx @@ -30,6 +30,7 @@ import { useBankCoreApiContext } from "../context/config.js"; import { withRuntimeErrorHandling } from "../utils.js"; import { assertUnreachable } from "./WithdrawalOperationPage.js"; import { LocalNotificationBanner } from "@gnu-taler/web-util/browser"; +import { useBackendState } from "../hooks/backend.js"; export function QrCodeSection({ withdrawUri, @@ -40,6 +41,9 @@ export function QrCodeSection({ }): VNode { const { i18n } = useTranslationContext(); const talerWithdrawUri = stringifyWithdrawUri(withdrawUri); + const { state: credentials } = useBackendState(); + const creds = credentials.status !== "loggedIn" ? undefined : credentials + useEffect(() => { //Taler Wallet WebExtension is listening to headers response and tab updates. //In the SPA there is no header response with the Taler URI so @@ -58,7 +62,8 @@ export function QrCodeSection({ async function doAbort() { await handleError(async () => { - const resp = await api.abortWithdrawalById(withdrawUri.withdrawalOperationId); + if (!creds) return; + const resp = await api.abortWithdrawalById(creds, withdrawUri.withdrawalOperationId); if (resp.type === "ok") { onAborted(); } else { diff --git a/packages/demobank-ui/src/pages/RegistrationPage.tsx b/packages/demobank-ui/src/pages/RegistrationPage.tsx @@ -96,7 +96,7 @@ function RegistrationForm({ onComplete, onCancel }: { onComplete: () => void, on : undefined, }); - async function doRegistrationAndLogin(name: string, username: string, password: string) { + async function doRegistrationAndLogin(name: string, username: string, password: string, onComplete: () => void) { await handleError(async () => { const creationResponse = await api.createAccount("" as AccessToken, { name, username, password }); if (creationResponse.type === "fail") { @@ -137,6 +137,12 @@ function RegistrationForm({ onComplete, onCancel }: { onComplete: () => void, on description: creationResponse.detail.hint as TranslatedString, debug: creationResponse.detail, }) + case "user-cant-set-debt": return notify({ + type: "error", + title: i18n.str`Only admin is allow to set debt limit.`, + description: creationResponse.detail.hint as TranslatedString, + debug: creationResponse.detail, + }) default: assertUnreachable(creationResponse) } } @@ -165,16 +171,18 @@ function RegistrationForm({ onComplete, onCancel }: { onComplete: () => void, on default: assertUnreachable(resp) } } + onComplete() }) } async function doRegistrationStep() { if (!username || !password || !name) return; - await doRegistrationAndLogin(name, username, password) - setUsername(undefined); - setPassword(undefined); - setRepeatPassword(undefined); - onComplete(); + await doRegistrationAndLogin(name, username, password, () => { + setUsername(undefined); + setPassword(undefined); + setRepeatPassword(undefined); + onComplete(); + }) } async function doRandomRegistration(tries: number = 3) { @@ -183,8 +191,8 @@ function RegistrationForm({ onComplete, onCancel }: { onComplete: () => void, on const pass = settings.simplePasswordForRandomAccounts ? "123" : getRandomPassword(); const username = `_${user.first}-${user.second}_` const name = `${user.first}, ${user.second}` - await doRegistrationAndLogin(name, username, pass) - onComplete(); + await doRegistrationAndLogin(name, username, pass, onComplete) + } return ( diff --git a/packages/demobank-ui/src/pages/WireTransfer.tsx b/packages/demobank-ui/src/pages/WireTransfer.tsx @@ -1,13 +1,12 @@ import { Amounts, TalerError } from "@gnu-taler/taler-util"; -import { notifyInfo, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { Loading, notifyInfo, useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; -import { ErrorLoading } from "@gnu-taler/web-util/browser"; -import { Loading } from "@gnu-taler/web-util/browser"; +import { ErrorLoadingWithDebug } from "../components/ErrorLoadingWithDebug.js"; import { useAccountDetails } from "../hooks/access.js"; -import { assertUnreachable } from "./WithdrawalOperationPage.js"; +import { useBackendState } from "../hooks/backend.js"; import { LoginForm } from "./LoginForm.js"; import { PaytoWireTransferForm } from "./PaytoWireTransferForm.js"; -import { useBackendState } from "../hooks/backend.js"; +import { assertUnreachable } from "./WithdrawalOperationPage.js"; export function WireTransfer({ toAccount, onRegister, onCancel, onSuccess }: { onSuccess?: () => void; toAccount?: string, onCancel?: () => void, onRegister?: () => void }): VNode { const { i18n } = useTranslationContext(); @@ -19,12 +18,12 @@ export function WireTransfer({ toAccount, onRegister, onCancel, onSuccess }: { o return <Loading /> } if (result instanceof TalerError) { - return <ErrorLoading error={result} /> + return <ErrorLoadingWithDebug error={result} /> } if (result.type === "fail") { switch (result.case) { - case "unauthorized": return <LoginForm reason="forbidden" /> - case "not-found": return <LoginForm reason="not-found" /> + case "unauthorized": return <LoginForm currentUser={account} /> + case "not-found": return <LoginForm currentUser={account} /> default: assertUnreachable(result) } } diff --git a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx @@ -20,24 +20,32 @@ import { PaytoUri, PaytoUriIBAN, PaytoUriTalerBank, + TalerError, TranslatedString, WithdrawUriResult } from "@gnu-taler/taler-util"; import { + Attention, + Loading, + LocalNotificationBanner, + ShowInputErrorLabel, notifyInfo, useLocalNotification, useTranslationContext } from "@gnu-taler/web-util/browser"; -import { Fragment, VNode, h } from "preact"; +import { ComponentChildren, Fragment, VNode, h } from "preact"; import { useMemo, useState } from "preact/hooks"; import { mutate } from "swr"; -import { ShowInputErrorLabel } from "@gnu-taler/web-util/browser"; +import { ErrorLoadingWithDebug } from "../components/ErrorLoadingWithDebug.js"; import { useBankCoreApiContext } from "../context/config.js"; +import { useWithdrawalDetails } from "../hooks/access.js"; +import { useBackendState } from "../hooks/backend.js"; import { usePreferences } from "../hooks/preferences.js"; -import { undefinedIfEmpty, withRuntimeErrorHandling } from "../utils.js"; +import { undefinedIfEmpty } from "../utils.js"; +import { LoginForm } from "./LoginForm.js"; import { RenderAmount } from "./PaytoWireTransferForm.js"; import { assertUnreachable } from "./WithdrawalOperationPage.js"; -import { LocalNotificationBanner } from "@gnu-taler/web-util/browser"; +import { OperationNotFound } from "./WithdrawalQRCode.js"; const logger = new Logger("WithdrawalConfirmationQuestion"); @@ -47,6 +55,7 @@ interface Props { details: { account: PaytoUri, reserve: string, + username: string, amount: AmountJson, } } @@ -60,7 +69,23 @@ export function WithdrawalConfirmationQuestion({ withdrawUri, }: Props): VNode { const { i18n } = useTranslationContext(); - const [settings, updateSettings] = usePreferences() + const [settings] = usePreferences() + const { state: credentials } = useBackendState(); + const creds = credentials.status !== "loggedIn" ? undefined : credentials + const withdrawalInfo = useWithdrawalDetails(withdrawUri.withdrawalOperationId) + if (!withdrawalInfo) { + return <Loading /> + } + if (withdrawalInfo instanceof TalerError) { + return <ErrorLoadingWithDebug error={withdrawalInfo} /> + } + if (withdrawalInfo.type === "fail") { + switch (withdrawalInfo.case) { + case "not-found": return <OperationNotFound onClose={onAborted} /> + case "invalid-id": return <OperationNotFound onClose={onAborted} /> + default: assertUnreachable(withdrawalInfo) + } + } const captchaNumbers = useMemo(() => { return { @@ -87,7 +112,8 @@ export function WithdrawalConfirmationQuestion({ async function doTransfer() { setBusy({}) await handleError(async () => { - const resp = await api.confirmWithdrawalById(withdrawUri.withdrawalOperationId); + if (!creds) return; + const resp = await api.confirmWithdrawalById(creds, withdrawUri.withdrawalOperationId); if (resp.type === "ok") { mutate(() => true)// clean any info that we have if (!settings.showWithdrawalSuccess) { @@ -135,7 +161,8 @@ export function WithdrawalConfirmationQuestion({ async function doCancel() { setBusy({}) await handleError(async () => { - const resp = await api.abortWithdrawalById(withdrawUri.withdrawalOperationId); + if (!creds) return; + const resp = await api.abortWithdrawalById(creds, withdrawUri.withdrawalOperationId); if (resp.type === "ok") { onAborted(); } else { @@ -176,66 +203,70 @@ export function WithdrawalConfirmationQuestion({ </h3> <div class="mt-3 text-sm leading-6"> - <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg"> - <div class="px-4 sm:px-0"> - <h2 class="text-base font-semibold text-gray-900"><i18n.Translate>Answer the next question to authorize the wire transfer.</i18n.Translate></h2> - </div> - <form - class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2" - autoCapitalize="none" - autoCorrect="off" - onSubmit={e => { - e.preventDefault() - }} - > - <div class="px-4 py-6 sm:p-8"> - <label for="withdraw-amount">{i18n.str`What is`} - <em> - {captchaNumbers.a} + {captchaNumbers.b} - </em> - ? - </label> - <div class="mt-2"> - <div class="relative rounded-md shadow-sm"> - <input - type="text" - // class="block w-full rounded-md border-0 py-1.5 pl-16 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" - aria-describedby="answer" - autoFocus - class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" - value={captchaAnswer ?? ""} - required + <ShouldBeSameUser username={details.username}> + <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg"> + <div class="px-4 sm:px-0"> + <h2 class="text-base font-semibold text-gray-900"><i18n.Translate>Answer the next question to authorize the wire transfer.</i18n.Translate></h2> + </div> + <form + class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2" + autoCapitalize="none" + autoCorrect="off" + onSubmit={e => { + e.preventDefault() + }} + > + <div class="px-4 py-6 sm:p-8"> + <label for="withdraw-amount">{i18n.str`What is`} + <em> + {captchaNumbers.a} + {captchaNumbers.b} + </em> + ? + </label> - name="answer" - id="answer" - autocomplete="off" - onChange={(e): void => { - setCaptchaAnswer(e.currentTarget.value) - }} - /> + <div class="mt-2"> + <div class="relative rounded-md shadow-sm"> + <input + type="text" + // class="block w-full rounded-md border-0 py-1.5 pl-16 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + aria-describedby="answer" + autoFocus + class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + value={captchaAnswer ?? ""} + required + + name="answer" + id="answer" + autocomplete="off" + onChange={(e): void => { + setCaptchaAnswer(e.currentTarget.value) + }} + /> + </div> + <ShowInputErrorLabel message={errors?.answer} isDirty={captchaAnswer !== undefined} /> </div> - <ShowInputErrorLabel message={errors?.answer} isDirty={captchaAnswer !== undefined} /> </div> - </div> - <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8"> - <button type="button" class="text-sm font-semibold leading-6 text-gray-900" - onClick={doCancel} - > - <i18n.Translate>Cancel</i18n.Translate></button> - <button type="submit" - class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" - disabled={!!errors} - onClick={(e) => { - e.preventDefault() - doTransfer() - }} - > - <i18n.Translate>Transfer</i18n.Translate> - </button> - </div> - </form> - </div> + <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8"> + <button type="button" class="text-sm font-semibold leading-6 text-gray-900" + onClick={doCancel} + > + <i18n.Translate>Cancel</i18n.Translate></button> + <button type="submit" + class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" + disabled={!!errors} + onClick={(e) => { + e.preventDefault() + doTransfer() + }} + > + <i18n.Translate>Transfer</i18n.Translate> + </button> + </div> + + </form> + </div> + </ShouldBeSameUser> </div> <div class="px-4 mt-4 "> <div class="w-full"> @@ -300,6 +331,26 @@ export function WithdrawalConfirmationQuestion({ </div> </div> - </Fragment> + </Fragment > ); } + +export function ShouldBeSameUser({ username, children }: { username: string, children: ComponentChildren }): VNode { + const { state: credentials } = useBackendState(); + const { i18n } = useTranslationContext() + if (credentials.status === "loggedOut") { + return <Fragment> + <Attention type="info" title={i18n.str`Authentication required`} /> + <LoginForm currentUser={username} fixedUser /> + </Fragment> + } + if (credentials.username !== username) { + return <Fragment> + <Attention type="warning" title={i18n.str`This operation was created with other username`} /> + <LoginForm currentUser={username} fixedUser /> + </Fragment> + } + return <Fragment> + {children} + </Fragment> +} +\ No newline at end of file diff --git a/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx b/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx @@ -21,11 +21,9 @@ import { WithdrawUriResult, parsePaytoUri } from "@gnu-taler/taler-util"; -import { notifyInfo, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { Attention, Loading, notifyInfo, useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; -import { Attention } from "@gnu-taler/web-util/browser"; -import { ErrorLoading } from "@gnu-taler/web-util/browser"; -import { Loading } from "@gnu-taler/web-util/browser"; +import { ErrorLoadingWithDebug } from "../components/ErrorLoadingWithDebug.js"; import { useWithdrawalDetails } from "../hooks/access.js"; import { QrCodeSection } from "./QrCodeSection.js"; import { WithdrawalConfirmationQuestion } from "./WithdrawalConfirmationQuestion.js"; @@ -53,19 +51,19 @@ export function WithdrawalQRCode({ return <Loading /> } if (result instanceof TalerError) { - return <ErrorLoading error={result} /> + return <ErrorLoadingWithDebug error={result} /> } if (result.type === "fail") { switch (result.case) { + case "invalid-id": case "not-found": return <OperationNotFound onClose={onClose} /> - case "invalid-id": return <OperationNotFound onClose={onClose} /> default: assertUnreachable(result) } } const { body: data } = result; - if (data.aborted) { + if (data.status === "aborted") { return <section id="main" class="content"> <h1 class="nav">{i18n.str`Operation aborted`}</h1> <section> @@ -93,7 +91,7 @@ export function WithdrawalQRCode({ </section> } - if (data.confirmation_done) { + if (data.status === "confirmed") { return <div class="relative ml-auto mr-auto transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-sm sm:p-6"> <div> <div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100"> @@ -128,7 +126,7 @@ export function WithdrawalQRCode({ } - if (!data.selection_done) { + if (data.status === "pending") { return ( <QrCodeSection withdrawUri={withdrawUri} @@ -160,6 +158,7 @@ export function WithdrawalQRCode({ <WithdrawalConfirmationQuestion withdrawUri={withdrawUri} details={{ + username: data.username, account, reserve: data.selected_reserve_pub, amount: Amounts.parseOrThrow(data.amount) @@ -173,7 +172,7 @@ export function WithdrawalQRCode({ } -function OperationNotFound({ onClose }: { onClose: () => void }): VNode { +export function OperationNotFound({ onClose }: { onClose: () => void }): VNode { const { i18n } = useTranslationContext(); return <div class="relative ml-auto mr-auto transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-sm sm:p-6"> <div> diff --git a/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx b/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx @@ -1,18 +1,15 @@ import { TalerCorebankApi, TalerError, TranslatedString } from "@gnu-taler/taler-util"; -import { notifyInfo, useLocalNotification, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { Loading, LocalNotificationBanner, notifyInfo, useLocalNotification, useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; -import { ErrorLoading } from "@gnu-taler/web-util/browser"; -import { Loading } from "@gnu-taler/web-util/browser"; +import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js"; import { useBankCoreApiContext } from "../../context/config.js"; import { useAccountDetails } from "../../hooks/access.js"; import { useBackendState } from "../../hooks/backend.js"; -import { undefinedIfEmpty, withRuntimeErrorHandling } from "../../utils.js"; import { LoginForm } from "../LoginForm.js"; import { ProfileNavigation } from "../ProfileNavigation.js"; import { assertUnreachable } from "../WithdrawalOperationPage.js"; import { AccountForm } from "../admin/AccountForm.js"; -import { LocalNotificationBanner } from "@gnu-taler/web-util/browser"; export function ShowAccountDetails({ account, @@ -31,7 +28,7 @@ export function ShowAccountDetails({ credentials.username === account : false const [update, setUpdate] = useState(false); - const [submitAccount, setSubmitAccount] = useState<TalerCorebankApi.AccountData | undefined>(); + const [submitAccount, setSubmitAccount] = useState<TalerCorebankApi.AccountReconfiguration | undefined>(); const [notification, notify, handleError] = useLocalNotification() const result = useAccountDetails(account); @@ -39,12 +36,12 @@ export function ShowAccountDetails({ return <Loading /> } if (result instanceof TalerError) { - return <ErrorLoading error={result} /> + return <ErrorLoadingWithDebug error={result} /> } if (result.type === "fail") { switch (result.case) { - case "not-found": return <LoginForm reason="not-found" /> - case "unauthorized": return <LoginForm reason="forbidden" /> + case "not-found": return <LoginForm currentUser={account} /> + case "unauthorized": return <LoginForm currentUser={account} /> default: assertUnreachable(result) } } @@ -55,15 +52,7 @@ export function ShowAccountDetails({ const resp = await api.updateAccount({ token: creds.token, username: account, - }, { - cashout_payto_uri: submitAccount.cashout_payto_uri, - challenge_contact_data: undefinedIfEmpty({ - email: submitAccount.contact_data?.email, - phone: submitAccount.contact_data?.phone, - }), - is_taler_exchange: false, - name: submitAccount.name, - }); + }, submitAccount); if (resp.type === "ok") { notifyInfo(i18n.str`Account updated`); @@ -82,9 +71,27 @@ export function ShowAccountDetails({ description: resp.detail.hint as TranslatedString, debug: resp.detail, }) - case "cant-change-legal-name-or-admin": return notify({ + case "user-cant-change-name": return notify({ type: "error", - title: i18n.str`Can't change legal name`, + title: i18n.str`You can't change the legal name, please contact the your account administrator.`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + }) + case "user-cant-change-debt": return notify({ + type: "error", + title: i18n.str`You can't change the debt limit, please contact the your account administrator.`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + }) + case "user-cant-change-cashout": return notify({ + type: "error", + title: i18n.str`You can't change the cashout address, please contact the your account administrator.`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + }) + case "user-cant-change-contact": return notify({ + type: "error", + title: i18n.str`You can't change the contact info, please contact the your account administrator.`, description: resp.detail.hint as TranslatedString, debug: resp.detail, }) @@ -99,7 +106,7 @@ export function ShowAccountDetails({ <Fragment> <LocalNotificationBanner notification={notification} /> {accountIsTheCurrentUser ? - <ProfileNavigation current="details" noCashout={credentials.status === "loggedIn" ? credentials.isUserAdministrator : undefined} /> + <ProfileNavigation current="details" /> : <h1 class="text-base font-semibold leading-6 text-gray-900"> <i18n.Translate>Account "{account}"</i18n.Translate> @@ -128,7 +135,6 @@ export function ShowAccountDetails({ <AccountForm focus={update} - noCashout={credentials.status === "loggedIn" ? credentials.isUserAdministrator : undefined} username={account} template={result.body} purpose={update ? "update" : "show"} diff --git a/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx b/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx @@ -61,16 +61,18 @@ export function UpdateAccountPassword({ type: "error", title: i18n.str`Not authorized to change the password, maybe the session is invalid.` }) - case "old-password-invalid-or-not-allowed": return notify({ - type: "error", - title: current ? - i18n.str`This user have no right on to change the password.` : - i18n.str`This user have no right on to change the password or the old password doesn't match.` - }) case "not-found": return notify({ type: "error", title: i18n.str`Account not found` }) + case "user-require-old-password": return notify({ + type: "error", + title: i18n.str`Old password need to be provided in order to change new one. If you don't have it contact your account administrator.` + }) + case "wrong-old-password": return notify({ + type: "error", + title: i18n.str`Your current password doesn't match, can't change to a new password.` + }) default: assertUnreachable(resp) } } @@ -81,7 +83,7 @@ export function UpdateAccountPassword({ <Fragment> <LocalNotificationBanner notification={notification} /> {accountIsTheCurrentUser ? - <ProfileNavigation current="credentials" noCashout={credentials.status === "loggedIn" ? credentials.isUserAdministrator : undefined} /> : + <ProfileNavigation current="credentials" /> : <h1 class="text-base font-semibold leading-6 text-gray-900"> <i18n.Translate>Account "{accountName}"</i18n.Translate> </h1> diff --git a/packages/demobank-ui/src/pages/admin/AccountForm.tsx b/packages/demobank-ui/src/pages/admin/AccountForm.tsx @@ -1,96 +1,208 @@ -import { PaytoString, TalerCorebankApi, buildPayto, parsePaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util"; +import { AmountString, Amounts, PaytoString, TalerCorebankApi, TranslatedString, buildPayto, parsePaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util"; import { CopyButton, ShowInputErrorLabel, useTranslationContext } from "@gnu-taler/web-util/browser"; import { ComponentChildren, Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; -import { PartialButDefined, RecursivePartial, WithIntermediate, undefinedIfEmpty, validateIBAN } from "../../utils.js"; -import { doAutoFocus } from "../PaytoWireTransferForm.js"; +import { useBankCoreApiContext } from "../../context/config.js"; +import { ErrorMessageMappingFor, PartialButDefined, WithIntermediate, undefinedIfEmpty, validateIBAN } from "../../utils.js"; +import { InputAmount, doAutoFocus } from "../PaytoWireTransferForm.js"; import { assertUnreachable } from "../WithdrawalOperationPage.js"; +import { getRandomPassword } from "../rnd.js"; +import { useBackendState } from "../../hooks/backend.js"; const IBAN_REGEX = /^[A-Z][A-Z0-9]*$/; const EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; const REGEX_JUST_NUMBERS_REGEX = /^\+[0-9 ]*$/; -export type AccountFormData = TalerCorebankApi.AccountData & { username: string } +export type AccountFormData = { + debit_threshold?: string, + isExchange?: boolean, + isPublic?: boolean, + name?: string, + username?: string, + payto_uri?: string, + cashout_payto_uri?: string, + email?: string, + phone?: string, +} +type ChangeByPurposeType = { + "create": (a: TalerCorebankApi.RegisterAccountRequest | undefined) => void, + "update": (a: TalerCorebankApi.AccountReconfiguration | undefined) => void, + "show": undefined +} /** - * Create valid account object to update or create - * Take template as initial values for the form - * Purpose indicate if all field al read only (show), part of them (update) - * or none (create) + * FIXME: + * is_public is missing on PATCH + * account email/password should require 2FA + * + * * @param param0 * @returns */ -export function AccountForm({ +export function AccountForm<PurposeType extends keyof ChangeByPurposeType>({ template, username, purpose, onChange, focus, - noCashout, children, }: { focus?: boolean, children: ComponentChildren, username?: string, - noCashout?: boolean, template: TalerCorebankApi.AccountData | undefined; - onChange: (a: AccountFormData | undefined) => void; - purpose: "create" | "update" | "show"; + onChange: ChangeByPurposeType[PurposeType]; + purpose: PurposeType; }): VNode { - const initial = initializeFromTemplate(username, template); - const [form, setForm] = useState(initial); + const { config } = useBankCoreApiContext() + const { i18n } = useTranslationContext(); + const { state: credentials } = useBackendState(); + const [form, setForm] = useState<AccountFormData>({}); + const [errors, setErrors] = useState< - RecursivePartial<typeof initial> | undefined + ErrorMessageMappingFor<typeof defaultValue> | undefined >(undefined); - const { i18n } = useTranslationContext(); - function updateForm(newForm: typeof initial): void { - const parsed = !newForm.cashout_payto_uri + + const defaultValue: AccountFormData = { + debit_threshold: Amounts.stringifyValue(template?.debit_threshold ??config.default_debit_threshold), + isExchange: template?.is_taler_exchange, + isPublic: template?.is_public, + name: template?.name ?? "", + cashout_payto_uri: stringifyIbanPayto(template?.cashout_payto_uri) ?? "" as PaytoString, + payto_uri: stringifyIbanPayto(template?.payto_uri) ?? "" as PaytoString, + email: template?.contact_data?.email ?? "", + phone: template?.contact_data?.phone ?? "", + username: username ?? "", + } + + const showingCurrentUserInfo = credentials.status !== "loggedIn" ? false : username === credentials.username + const userIsAdmin = credentials.status !== "loggedIn" ? false : credentials.isUserAdministrator + + const editableUsername = (purpose === "create") + const editableName = (purpose === "create" || purpose === "update" && (config.allow_edit_name || userIsAdmin)) + const editableCashout = showingCurrentUserInfo && (purpose === "create" || purpose === "update" && (config.allow_edit_cashout_payto_uri || userIsAdmin)) + const editableThreshold = userIsAdmin && (purpose === "create" || purpose === "update") + const editableAccount = purpose === "create" && userIsAdmin + + function updateForm(newForm: typeof defaultValue): void { + const cashoutParsed = !newForm.cashout_payto_uri ? undefined : buildPayto("iban", newForm.cashout_payto_uri, undefined);; - const errors = undefinedIfEmpty<RecursivePartial<typeof initial>>({ + const internalParsed = !newForm.payto_uri + ? undefined + : buildPayto("iban", newForm.payto_uri, undefined);; + + const trimmedAmountStr = newForm.debit_threshold?.trim(); + const parsedAmount = Amounts.parse(`${config.currency}:${trimmedAmountStr}`); + + const errors = undefinedIfEmpty<ErrorMessageMappingFor<typeof defaultValue>>({ cashout_payto_uri: (!newForm.cashout_payto_uri - ? undefined - : !parsed - ? i18n.str`does not follow the pattern` - : !parsed.isKnown || parsed.targetType !== "iban" - ? i18n.str`only "IBAN" target are supported` - : !IBAN_REGEX.test(parsed.iban) - ? i18n.str`IBAN should have just uppercased letters and numbers` - : validateIBAN(parsed.iban, i18n)) as PaytoString, - contact_data: undefinedIfEmpty({ - email: !newForm.contact_data?.email - ? undefined - : !EMAIL_REGEX.test(newForm.contact_data.email) - ? i18n.str`it should be an email` - : undefined, - phone: !newForm.contact_data?.phone - ? undefined - : !newForm.contact_data.phone.startsWith("+") - ? i18n.str`should start with +` - : !REGEX_JUST_NUMBERS_REGEX.test(newForm.contact_data.phone) - ? i18n.str`phone number can't have other than numbers` - : undefined, - }), - name: !newForm.name ? i18n.str`required` : undefined, - username: !newForm.username ? i18n.str`required` : undefined, + ? undefined : + !editableCashout ? undefined : + !cashoutParsed + ? i18n.str`does not follow the pattern` : + !cashoutParsed.isKnown || cashoutParsed.targetType !== "iban" + ? i18n.str`only "IBAN" target are supported` : + !IBAN_REGEX.test(cashoutParsed.iban) + ? i18n.str`IBAN should have just uppercased letters and numbers` : + validateIBAN(cashoutParsed.iban, i18n)), + payto_uri: (!newForm.payto_uri + ? undefined : + !editableAccount ? undefined : + !internalParsed + ? i18n.str`does not follow the pattern` : + !internalParsed.isKnown || internalParsed.targetType !== "iban" + ? i18n.str`only "IBAN" target are supported` : + !IBAN_REGEX.test(internalParsed.iban) + ? i18n.str`IBAN should have just uppercased letters and numbers` : + validateIBAN(internalParsed.iban, i18n)), + email: !newForm.email + ? undefined : + !EMAIL_REGEX.test(newForm.email) + ? i18n.str`it should be an email` : + undefined, + phone: !newForm.phone + ? undefined : + !newForm.phone.startsWith("+") // FIXME: better phone number check + ? i18n.str`should start with +` : + !REGEX_JUST_NUMBERS_REGEX.test(newForm.phone) + ? i18n.str`phone number can't have other than numbers` + : + undefined, + debit_threshold: !editableThreshold ? undefined : + !trimmedAmountStr ? undefined : + !parsedAmount ? i18n.str`not valid` : + undefined, + name: !editableName ? undefined : //disabled + !newForm.name ? i18n.str`required` : undefined, + username: !editableUsername ? undefined : !newForm.username ? i18n.str`required` : undefined, }); setErrors(errors); + setForm(newForm); + if (!onChange) return; + if (errors) { onChange(undefined) } else { - const cashout = !newForm.cashout_payto_uri? undefined :buildPayto("iban", newForm.cashout_payto_uri, undefined) - const account: AccountFormData = { - ...newForm as any, - cashout_payto_uri: !cashout ? undefined : stringifyPaytoUri(cashout) + const cashout = !newForm.cashout_payto_uri ? undefined : buildPayto("iban", newForm.cashout_payto_uri, undefined) + const cashoutURI = !cashout ? undefined : stringifyPaytoUri(cashout) + + const internal = !newForm.payto_uri ? undefined : buildPayto("iban", newForm.payto_uri, undefined); + const internalURI = !internal ? undefined : stringifyPaytoUri(internal) + + const threshold = !parsedAmount ? undefined : Amounts.stringify(parsedAmount) + + switch (purpose) { + case "create": { + //typescript doesn't correctly narrow a generic type + const callback = onChange as ChangeByPurposeType["create"] + const result: TalerCorebankApi.RegisterAccountRequest = { + name: newForm.name!, + password: getRandomPassword(), + username: newForm.username!, + contact_data: undefinedIfEmpty({ + email: newForm.email, + phone: newForm.phone, + }), + debit_threshold: threshold ?? config.default_debit_threshold, + cashout_payto_uri: cashoutURI, + payto_uri: internalURI, + is_public: !!newForm.isPublic, + is_taler_exchange: !!newForm.isExchange, + } + callback(result) + return; + } + case "update": { + //typescript doesn't correctly narrow a generic type + const callback = onChange as ChangeByPurposeType["update"] + + const result: TalerCorebankApi.AccountReconfiguration = { + cashout_payto_uri: cashoutURI, + contact_data: undefinedIfEmpty({ + email: newForm.email ?? template?.contact_data?.email, + phone: newForm.phone ?? template?.contact_data?.phone, + }), + debit_threshold: threshold, + is_public: !!newForm.isPublic, + name: newForm.name, + } + callback(result) + return; + } + case "show": { + return; + } + default: { + assertUnreachable(purpose) + } } - onChange(account); } } - return ( <form class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2" @@ -109,7 +221,7 @@ export function AccountForm({ for="username" > {i18n.str`Username`} - {purpose === "create" && <b style={{ color: "red" }}> *</b>} + {editableUsername && <b style={{ color: "red" }}> *</b>} </label> <div class="mt-2"> <input @@ -119,8 +231,8 @@ export function AccountForm({ name="username" id="username" data-error={!!errors?.username && form.username !== undefined} - disabled={purpose !== "create"} - value={form.username ?? ""} + disabled={!editableUsername} + value={form.username ?? defaultValue.username} onChange={(e) => { form.username = e.currentTarget.value; updateForm(structuredClone(form)); @@ -144,7 +256,7 @@ export function AccountForm({ for="name" > {i18n.str`Name`} - {purpose === "create" && <b style={{ color: "red" }}> *</b>} + {editableName && <b style={{ color: "red" }}> *</b>} </label> <div class="mt-2"> <input @@ -153,8 +265,8 @@ export function AccountForm({ name="name" data-error={!!errors?.name && form.name !== undefined} id="name" - disabled={purpose === "show"} - value={form.name ?? ""} + disabled={!editableName} + value={form.name ?? defaultValue.name} onChange={(e) => { form.name = e.currentTarget.value; updateForm(structuredClone(form)); @@ -173,7 +285,20 @@ export function AccountForm({ </div> - {purpose !== "create" && (<RenderPaytoDisabledField paytoURI={form.payto_uri as PaytoString} />)} + <PaytoField + type="iban" + name="internal-account" + label={i18n.str`Internal IBAN`} + help={purpose === "create" ? + i18n.str`if empty a random account number will be assigned` : + i18n.str`account identification for bank transfer`} + value={(form.payto_uri ?? defaultValue.payto_uri) as PaytoString} + disabled={!editableAccount} + error={errors?.payto_uri} + onChange={(e) => { + form.payto_uri = e as PaytoString + updateForm(structuredClone(form)) + }} /> <div class="sm:col-span-5"> <label @@ -181,7 +306,6 @@ export function AccountForm({ for="email" > {i18n.str`Email`} - {purpose === "create" && <b style={{ color: "red" }}> *</b>} </label> <div class="mt-2"> <input @@ -189,23 +313,18 @@ export function AccountForm({ class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" name="email" id="email" - data-error={!!errors?.contact_data?.email && form.contact_data?.email !== undefined} + data-error={!!errors?.email && form.email !== undefined} disabled={purpose === "show"} - value={form.contact_data?.email ?? ""} + value={form.email ?? defaultValue.email} onChange={(e) => { - if (form.contact_data) { - form.contact_data.email = e.currentTarget.value; - if (!form.contact_data.email) { - form.contact_data.email = undefined - } - updateForm(structuredClone(form)); - } + form.email = e.currentTarget.value; + updateForm(structuredClone(form)); }} autocomplete="off" /> <ShowInputErrorLabel - message={errors?.contact_data?.email} - isDirty={form.contact_data?.email !== undefined} + message={errors?.email} + isDirty={form.email !== undefined} /> </div> </div> @@ -216,7 +335,6 @@ export function AccountForm({ for="phone" > {i18n.str`Phone`} - {purpose === "create" && <b style={{ color: "red" }}> *</b>} </label> <div class="mt-2"> <input @@ -225,233 +343,254 @@ export function AccountForm({ name="phone" id="phone" disabled={purpose === "show"} - value={form.contact_data?.phone ?? ""} - data-error={!!errors?.contact_data?.phone && form.contact_data?.phone !== undefined} + value={form.phone ?? defaultValue.phone} + data-error={!!errors?.phone && form.phone !== undefined} onChange={(e) => { - if (form.contact_data) { - form.contact_data.phone = e.currentTarget.value; - if (!form.contact_data.email) { - form.contact_data.email = undefined - } - updateForm(structuredClone(form)); - } + form.phone = e.currentTarget.value; + updateForm(structuredClone(form)); }} - // placeholder="" autocomplete="off" /> <ShowInputErrorLabel - message={errors?.contact_data?.phone} - isDirty={form.contact_data?.phone !== undefined} + message={errors?.phone} + isDirty={form.phone !== undefined} /> </div> </div> + {showingCurrentUserInfo && + <PaytoField + type="iban" + name="cashout-account" + label={i18n.str`Cashout IBAN`} + help={i18n.str`account number where the money is going to be sent when doing cashouts`} + value={(form.cashout_payto_uri ?? defaultValue.cashout_payto_uri) as PaytoString} + disabled={!editableCashout} + error={errors?.cashout_payto_uri} + onChange={(e) => { + form.cashout_payto_uri = e as PaytoString + updateForm(structuredClone(form)) + }} /> + } + + <div class="sm:col-span-5"> + <label for="debit" class="block text-sm font-medium leading-6 text-gray-900">{i18n.str`Max debt`}</label> + <InputAmount + name="debit" + left + currency={config.currency} + value={form.debit_threshold ?? defaultValue.debit_threshold} + onChange={!editableThreshold ? undefined : (e) => { + form.debit_threshold = e as AmountString + updateForm(structuredClone(form)) + }} + /> + <ShowInputErrorLabel + message={errors?.debit_threshold ? String(errors?.debit_threshold) : undefined} + isDirty={form.debit_threshold !== undefined} + /> + <p class="mt-2 text-sm text-gray-500" >how much is user able to transfer </p> + </div> - {!noCashout && + {purpose !== "create" || !userIsAdmin ? undefined : <div class="sm:col-span-5"> - <label - class="block text-sm font-medium leading-6 text-gray-900" - for="cashout" - > - {i18n.str`Cashout IBAN`} - {purpose !== "show" && <b style={{ color: "red" }}> *</b>} - </label> - <div class="mt-2"> - <input - type="text" - ref={focus && purpose === "update" ? doAutoFocus : undefined} - data-error={!!errors?.cashout_payto_uri && form.cashout_payto_uri !== undefined} - class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" - name="cashout" - id="cashout" - disabled={purpose === "show"} - value={form.cashout_payto_uri ?? ""} - onChange={(e) => { - form.cashout_payto_uri = e.currentTarget.value as PaytoString; - if (!form.cashout_payto_uri) { - form.cashout_payto_uri= undefined - } - updateForm(structuredClone(form)); - }} - autocomplete="off" - /> - <ShowInputErrorLabel - message={errors?.cashout_payto_uri} - isDirty={form.cashout_payto_uri !== undefined} - /> + <div class="flex items-center justify-between"> + <span class="flex flex-grow flex-col"> + <span class="text-sm text-black font-medium leading-6 " id="availability-label"> + <i18n.Translate>Is an exchange</i18n.Translate> + </span> + </span> + <button type="button" data-enabled={form.isExchange ?? defaultValue.isExchange ? "true" : "false"} class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" role="switch" aria-checked="false" aria-labelledby="availability-label" aria-describedby="availability-description" + + onClick={() => { + form.isExchange = !form.isExchange + updateForm(structuredClone(form)) + }}> + <span aria-hidden="true" data-enabled={form.isExchange ?? defaultValue.isExchange ? "true" : "false"} class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"></span> + </button> </div> - <p class="mt-2 text-sm text-gray-500" > - <i18n.Translate>account number where the money is going to be sent when doing cashouts</i18n.Translate> - </p> + </div>} + + <div class="sm:col-span-5"> + <div class="flex items-center justify-between"> + <span class="flex flex-grow flex-col"> + <span class="text-sm text-black font-medium leading-6 " id="availability-label"> + <i18n.Translate>Is public</i18n.Translate> + </span> + </span> + <button type="button" data-enabled={form.isPublic ?? defaultValue.isPublic ? "true" : "false"} class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" role="switch" aria-checked="false" aria-labelledby="availability-label" aria-describedby="availability-description" + + onClick={() => { + form.isPublic = !form.isPublic + updateForm(structuredClone(form)) + }}> + <span aria-hidden="true" data-enabled={form.isPublic ?? defaultValue.isPublic ? "true" : "false"} class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"></span> + </button> </div> - } + <p class="mt-2 text-sm text-gray-500" > + <i18n.Translate>public accounts have their balance publicly accesible</i18n.Translate> + </p> + </div> </div> </div> + <pre> + {JSON.stringify(errors, undefined, 2)} + </pre> {children} </form> ); } -function initializeFromTemplate( - username: string | undefined, - account: TalerCorebankApi.AccountData | undefined, -): WithIntermediate<AccountFormData> { - const emptyAccount = { - cashout_payto_uri: undefined, - contact_data: undefined, - payto_uri: undefined, - balance: undefined, - debit_threshold: undefined, - name: undefined, - }; - const emptyContact = { - email: undefined, - phone: undefined, - }; - - const initial: PartialButDefined<TalerCorebankApi.AccountData> = - structuredClone(account) ?? emptyAccount; - if (typeof initial.contact_data === "undefined") { - initial.contact_data = emptyContact; - } - if (initial.cashout_payto_uri) { - const ac = parsePaytoUri(initial.cashout_payto_uri) - if (ac?.isKnown && ac.targetType === "iban") { - // we are using the cashout field for the iban number - initial.cashout_payto_uri = ac.targetPath as any - } - } - const result: WithIntermediate<AccountFormData> = initial as any // FIXME: check types - result.username = username - - return initial as any; +function stringifyIbanPayto(s: PaytoString | undefined): string | undefined { + if (s === undefined) return undefined + const p = parsePaytoUri(s) + if (p === undefined) return undefined + if (!p.isKnown) return undefined + if (p.targetType !== "iban") return undefined + return p.iban } +{/* <div class="sm:col-span-5"> + <label + class="block text-sm font-medium leading-6 text-gray-900" + for="cashout" + > + {} + </label> + <div class="mt-2"> + <input + type="text" + ref={focus && purpose === "update" ? doAutoFocus : undefined} + data-error={!!errors?.cashout_payto_uri && form.cashout_payto_uri !== undefined} + class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + name="cashout" + id="cashout" + disabled={purpose === "show"} + value={form.cashout_payto_uri ?? defaultValue.cashout_payto_uri} + onChange={(e) => { + form.cashout_payto_uri = e.currentTarget.value as PaytoString; + if (!form.cashout_payto_uri) { + form.cashout_payto_uri = undefined + } + updateForm(structuredClone(form)); + }} + autocomplete="off" + /> + <ShowInputErrorLabel + message={errors?.cashout_payto_uri} + isDirty={form.cashout_payto_uri !== undefined} + /> + </div> + <p class="mt-2 text-sm text-gray-500" > + <i18n.Translate></i18n.Translate> + </p> + </div> */} -function RenderPaytoDisabledField({ paytoURI }: { paytoURI: PaytoString | undefined }): VNode { - const { i18n } = useTranslationContext() - const payto = parsePaytoUri(paytoURI ?? ""); - if (payto?.isKnown) { - if (payto.targetType === "iban") { - const value = payto.iban; - return <div class="sm:col-span-5"> - <label - class="block text-sm font-medium leading-6 text-gray-900" - for="internal-iban" - > - {i18n.str`Internal IBAN`} - </label> - <div class="mt-2"> - <div class="flex justify-between"> - <input - type="text" - class="mr-4 w-full block-inline disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" - name="internal-iban" - id="internal-iban" - disabled={true} - value={value ?? ""} - /> - <CopyButton - class="p-2 rounded-full text-black shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 " - getContent={() => value ?? ""} - /> - </div> - </div> - <p class="mt-2 text-sm text-gray-500" > - <i18n.Translate>international bank account number</i18n.Translate> - </p> - </div> - } - if (payto.targetType === "x-taler-bank") { - const value = payto.account; - return <div class="sm:col-span-5"> - <label - class="block text-sm font-medium leading-6 text-gray-900" - for="account-id" - > - {i18n.str`Account ID`} - </label> - <div class="mt-2"> - <div class="flex justify-between"> - <input - type="text" - class="mr-4 w-full block-inline disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" - name="account-id" - id="account-id" - disabled={true} - value={value ?? ""} - /> - <CopyButton - class="p-2 rounded-full text-black shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 " - getContent={() => value ?? ""} - /> - </div> +function PaytoField({ name, label, help, type, value, disabled, onChange, error }: { error: TranslatedString | undefined, name: string, label: TranslatedString, help: TranslatedString, onChange: (s: string) => void, type: "iban" | "x-taler-bank" | "bitcoin", disabled?: boolean, value: string | undefined }): VNode { + if (type === "iban") { + return <div class="sm:col-span-5"> + <label + class="block text-sm font-medium leading-6 text-gray-900" + for={name} + > + {label} + </label> + <div class="mt-2"> + <div class="flex justify-between"> + <input + type="text" + class="mr-4 w-full block-inline disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + name={name} + id={name} + disabled={disabled} + value={value ?? ""} + onChange={(e) => { + onChange(e.currentTarget.value) + }} + /> + <CopyButton + class="p-2 rounded-full text-black shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 " + getContent={() => value ?? ""} + /> </div> - <p class="mt-2 text-sm text-gray-500" > - <i18n.Translate>internal account id</i18n.Translate> - </p> + <ShowInputErrorLabel + message={error} + isDirty={value !== undefined} + /> </div> - } - if (payto.targetType === "bitcoin") { - const value = payto.targetPath; - return <div class="sm:col-span-5"> - <label - class="block text-sm font-medium leading-6 text-gray-900" - for="account-id" - > - {i18n.str`Bitcoin address`} - </label> - <div class="mt-2"> - <div class="flex justify-between"> - <input - type="text" - class="mr-4 w-full block-inline disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" - name="account-id" - id="account-id" - disabled={true} - value={value ?? ""} - /> - <CopyButton - class="p-2 rounded-full text-black shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 " - getContent={() => value ?? ""} - /> - </div> + <p class="mt-2 text-sm text-gray-500" > + {help} + </p> + </div> + } + if (type === "x-taler-bank") { + return <div class="sm:col-span-5"> + <label + class="block text-sm font-medium leading-6 text-gray-900" + for={name} + > + {label} + </label> + <div class="mt-2"> + <div class="flex justify-between"> + <input + type="text" + class="mr-4 w-full block-inline disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + name={name} + id={name} + disabled={disabled} + value={value ?? ""} + /> + <CopyButton + class="p-2 rounded-full text-black shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 " + getContent={() => value ?? ""} + /> </div> - <p class="mt-2 text-sm text-gray-500" > - <i18n.Translate>bitcoin address</i18n.Translate> - </p> + <ShowInputErrorLabel + message={error} + isDirty={value !== undefined} + /> </div> - } - assertUnreachable(payto) + <p class="mt-2 text-sm text-gray-500" > + {/* <i18n.Translate>internal account id</i18n.Translate> */} + {help} + </p> + </div> } - - const value = paytoURI ?? "" - return <div class="sm:col-span-5"> - <label - class="block text-sm font-medium leading-6 text-gray-900" - for="internal-payto" - > - {i18n.str`Internal account`} - </label> - <div class="mt-2"> - <div class="flex justify-between"> - <input - type="text" - class="mr-4 w-full block-inline disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" - name="internal-payto" - id="internal-payto" - disabled={true} - value={value ?? ""} - /> - <CopyButton - class="p-2 rounded-full text-black shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 " - getContent={() => value ?? ""} - /> + if (type === "bitcoin") { + return <div class="sm:col-span-5"> + <label + class="block text-sm font-medium leading-6 text-gray-900" + for={name} + > + {label} + </label> + <div class="mt-2"> + <div class="flex justify-between"> + <input + type="text" + class="mr-4 w-full block-inline disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + name={name} + id={name} + disabled={disabled} + value={value ?? ""} + /> + <CopyButton + class="p-2 rounded-full text-black shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 " + getContent={() => value ?? ""} + /> + <ShowInputErrorLabel + message={error} + isDirty={value !== undefined} + /> + </div> </div> + <p class="mt-2 text-sm text-gray-500" > + {/* <i18n.Translate>bitcoin address</i18n.Translate> */} + {help} + </p> </div> - <p class="mt-2 text-sm text-gray-500" > - <i18n.Translate>generic payto URI</i18n.Translate> - </p> - </div> + } + assertUnreachable(type) } diff --git a/packages/demobank-ui/src/pages/admin/AccountList.tsx b/packages/demobank-ui/src/pages/admin/AccountList.tsx @@ -1,8 +1,7 @@ import { Amounts, TalerError } from "@gnu-taler/taler-util"; -import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { Loading, useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; -import { ErrorLoading } from "@gnu-taler/web-util/browser"; -import { Loading } from "@gnu-taler/web-util/browser"; +import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js"; import { useBankCoreApiContext } from "../../context/config.js"; import { useBusinessAccounts } from "../../hooks/circuit.js"; import { RenderAmount } from "../PaytoWireTransferForm.js"; @@ -26,7 +25,7 @@ export function AccountList({ onRemoveAccount, onShowAccountDetails, onUpdateAcc return <Loading /> } if (result instanceof TalerError) { - return <ErrorLoading error={result} /> + return <ErrorLoadingWithDebug error={result} /> } if (result.data.type === "fail") { switch (result.data.case) { diff --git a/packages/demobank-ui/src/pages/admin/AdminHome.tsx b/packages/demobank-ui/src/pages/admin/AdminHome.tsx @@ -1,14 +1,15 @@ import { AmountString, Amounts, CurrencySpecification, TalerCorebankApi, TalerError, assertUnreachable } from "@gnu-taler/taler-util"; -import { ErrorLoading, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { format, getDate, getHours, getMonth, getYear, setDate, setHours, setMonth, setYear, sub } from "date-fns"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js"; import { Transactions } from "../../components/Transactions/index.js"; +import { useBankCoreApiContext } from "../../context/config.js"; import { useConversionInfo, useLastMonitorInfo } from "../../hooks/circuit.js"; import { RenderAmount } from "../PaytoWireTransferForm.js"; import { WireTransfer } from "../WireTransfer.js"; import { AccountList } from "./AccountList.js"; -import { useBankCoreApiContext } from "../../context/config.js"; -import { format, getDate, getHours, getMonth, getYear, setDate, setHours, setMonth, setYear, sub } from "date-fns"; /** @@ -53,7 +54,7 @@ function getDateForTimeframe(which: number, timeframe: TalerCorebankApi.MonitorT assertUnreachable(timeframe) } -function getTimeframesForDate(time: Date, timeframe: TalerCorebankApi.MonitorTimeframeParam): { current: number, previous: number } { +export function getTimeframesForDate(time: Date, timeframe: TalerCorebankApi.MonitorTimeframeParam): { current: number, previous: number } { switch (timeframe) { case TalerCorebankApi.MonitorTimeframeParam.hour: return { current: getHours(sub(time, { hours: 1 })), @@ -90,7 +91,7 @@ function Metrics(): VNode { const resp = useLastMonitorInfo(params.current, params.previous, metricType); if (!resp) return <Fragment />; if (resp instanceof TalerError) { - return <ErrorLoading error={resp} /> + return <ErrorLoadingWithDebug error={resp} /> } if (resp.current.type !== "ok" || resp.previous.type !== "ok") { return <Fragment /> @@ -182,6 +183,13 @@ function Metrics(): VNode { /> </div> </dl> + <div class="flex justify-end mt-2"> + <a href="#/download-stats" + class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" + ><i18n.Translate> + download stats as csv + </i18n.Translate></a> + </div> </Fragment> } diff --git a/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx b/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx @@ -17,31 +17,33 @@ export function CreateNewAccount({ onCreateSuccess: () => void; }): VNode { const { i18n } = useTranslationContext(); - // const { createAccount } = useAdminAccountAPI(); const { state: credentials } = useBackendState() const token = credentials.status !== "loggedIn" ? undefined : credentials.token const { api } = useBankCoreApiContext(); - const [submitAccount, setSubmitAccount] = useState<AccountFormData | undefined>(); + const [submitAccount, setSubmitAccount] = useState<TalerCorebankApi.RegisterAccountRequest | undefined>(); const [notification, notify, handleError] = useLocalNotification() async function doCreate() { if (!submitAccount || !token) return; await handleError(async () => { - const account: TalerCorebankApi.RegisterAccountRequest = { - cashout_payto_uri: submitAccount.cashout_payto_uri, - challenge_contact_data: submitAccount.contact_data, - internal_payto_uri: submitAccount.payto_uri, - name: submitAccount.name, - username: submitAccount.username,//FIXME: not in account data - password: getRandomPassword(), - }; + // const account: TalerCorebankApi.RegisterAccountRequest = { + // cashout_payto_uri: submitAccount.cashout_payto_uri, + // challenge_contact_data: submitAccount.challenge_contact_data, + // internal_payto_uri: submitAccount.internal_payto_uri, + // debit_threshold: submitAccount.debit_threshold, + // is_public: submitAccount.is_public, + // is_taler_exchange: submitAccount.is_taler_exchange, + // name: submitAccount.name, + // username: submitAccount.username, + // password: getRandomPassword(), + // }; - const resp = await api.createAccount(token, account); + const resp = await api.createAccount(token, submitAccount); if (resp.type === "ok") { mutate(() => true)// clean account list notifyInfo( - i18n.str`Account created with password "${account.password}". The user must change the password on the next login.`, + i18n.str`Account created with password "${submitAccount.password}". The user must change the password on the next login.`, ); onCreateSuccess(); } else { @@ -82,6 +84,12 @@ export function CreateNewAccount({ description: resp.detail.hint as TranslatedString, debug: resp.detail, }) + case "user-cant-set-debt": return notify({ + type: "error", + title: i18n.str`Only admin is allow to set debt limit.`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + }) default: assertUnreachable(resp) } } diff --git a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx @@ -1,7 +1,8 @@ import { Amounts, TalerError, TranslatedString } from "@gnu-taler/taler-util"; -import { Attention, ErrorLoading, Loading, LocalNotificationBanner, ShowInputErrorLabel, notifyInfo, useLocalNotification, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { Attention, Loading, LocalNotificationBanner, ShowInputErrorLabel, notifyInfo, useLocalNotification, useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; +import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js"; import { useBankCoreApiContext } from "../../context/config.js"; import { useAccountDetails } from "../../hooks/access.js"; import { useBackendState } from "../../hooks/backend.js"; @@ -34,12 +35,12 @@ export function RemoveAccount({ return <Loading /> } if (result instanceof TalerError) { - return <ErrorLoading error={result} /> + return <ErrorLoadingWithDebug error={result} /> } if (result.type === "fail") { switch (result.case) { - case "unauthorized": return <LoginForm reason="forbidden" /> - case "not-found": return <LoginForm reason="not-found" /> + case "unauthorized": return <LoginForm currentUser={account} /> + case "not-found": return <LoginForm currentUser={account} /> default: assertUnreachable(result) } } diff --git a/packages/demobank-ui/src/pages/business/CreateCashout.tsx b/packages/demobank-ui/src/pages/business/CreateCashout.tsx @@ -23,7 +23,6 @@ import { } from "@gnu-taler/taler-util"; import { Attention, - ErrorLoading, Loading, LocalNotificationBanner, ShowInputErrorLabel, @@ -33,7 +32,7 @@ import { } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useEffect, useState } from "preact/hooks"; -import { mutate } from "swr"; +import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js"; import { useBankCoreApiContext } from "../../context/config.js"; import { useAccountDetails } from "../../hooks/access.js"; import { useBackendState } from "../../hooks/backend.js"; @@ -48,7 +47,6 @@ import { import { LoginForm } from "../LoginForm.js"; import { InputAmount, RenderAmount, doAutoFocus } from "../PaytoWireTransferForm.js"; import { assertUnreachable } from "../WithdrawalOperationPage.js"; -import { getRandomPassword, getRandomUsername } from "../rnd.js"; interface Props { account: string; @@ -97,12 +95,12 @@ export function CreateCashout({ return <Loading /> } if (resultAccount instanceof TalerError) { - return <ErrorLoading error={resultAccount} /> + return <ErrorLoadingWithDebug error={resultAccount} /> } if (resultAccount.type === "fail") { switch (resultAccount.case) { - case "unauthorized": return <LoginForm reason="forbidden" /> - case "not-found": return <LoginForm reason="not-found" /> + case "unauthorized": return <LoginForm currentUser={accountName} /> + case "not-found": return <LoginForm currentUser={accountName} /> default: assertUnreachable(resultAccount) } } @@ -111,7 +109,7 @@ export function CreateCashout({ } if (info instanceof TalerError) { - return <ErrorLoading error={info} /> + return <ErrorLoadingWithDebug error={info} /> } const conversionInfo = info.body.conversion_rate @@ -432,61 +430,64 @@ export function CreateCashout({ )} {/* channel */} - <div class="sm:col-span-5"> - <label - class="block text-sm font-medium leading-6 text-gray-900" - for="channel" - > - {i18n.str`Confirmation the operation using`} - </label> - - <div class="mt-2 max-w-xl text-sm text-gray-500"> - <div class="px-4 mt-4 grid grid-cols-1 gap-y-6"> - - <label onClick={() => { - if (!resultAccount.body.contact_data?.email) return; - form.channel = TanChannel.EMAIL - updateForm(structuredClone(form)) - }} data-disabled={!resultAccount.body.contact_data?.email} data-selected={form.channel === TanChannel.EMAIL} - class="relative flex data-[disabled=false]:cursor-pointer rounded-lg border bg-white data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"> - <input type="radio" name="channel" value="Newsletter" class="sr-only" /> - <span class="flex flex-1"> - <span class="flex flex-col"> - <span id="project-type-0-label" class="block text-sm font-medium text-gray-900 "> - <i18n.Translate>Email</i18n.Translate> + {config.supported_tan_channels.length === 0 ? undefined : + <div class="sm:col-span-5"> + <label + class="block text-sm font-medium leading-6 text-gray-900" + for="channel" + > + {i18n.str`Confirmation the operation using`} + </label> + <div class="mt-2 max-w-xl text-sm text-gray-500"> + <div class="px-4 mt-4 grid grid-cols-1 gap-y-6"> + {config.supported_tan_channels.indexOf(TanChannel.EMAIL) === -1 ? undefined : + <label onClick={() => { + if (!resultAccount.body.contact_data?.email) return; + form.channel = TanChannel.EMAIL + updateForm(structuredClone(form)) + }} data-disabled={!resultAccount.body.contact_data?.email} data-selected={form.channel === TanChannel.EMAIL} + class="relative flex data-[disabled=false]:cursor-pointer rounded-lg border bg-white data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"> + <input type="radio" name="channel" value="Newsletter" class="sr-only" /> + <span class="flex flex-1"> + <span class="flex flex-col"> + <span id="project-type-0-label" class="block text-sm font-medium text-gray-900 "> + <i18n.Translate>Email</i18n.Translate> + </span> + {!resultAccount.body.contact_data?.email && i18n.str`add a email in your profile to enable this option`} + </span> </span> - {!resultAccount.body.contact_data?.email && i18n.str`add a email in your profile to enable this option`} - </span> - </span> - <svg data-selected={form.channel === TanChannel.EMAIL} class="h-5 w-5 text-indigo-600 data-[selected=false]:hidden" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"> - <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" /> - </svg> - </label> - - <label onClick={() => { - if (!resultAccount.body.contact_data?.phone) return; - form.channel = TanChannel.SMS - updateForm(structuredClone(form)) - }} data-disabled={!resultAccount.body.contact_data?.phone} data-selected={form.channel === TanChannel.SMS} - class="relative flex data-[disabled=false]:cursor-pointer rounded-lg border data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"> - <input type="radio" name="channel" value="Existing Customers" class="sr-only" /> - <span class="flex flex-1"> - <span class="flex flex-col"> - <span id="project-type-1-label" class="block text-sm font-medium text-gray-900"> - <i18n.Translate>SMS</i18n.Translate> + <svg data-selected={form.channel === TanChannel.EMAIL} class="h-5 w-5 text-indigo-600 data-[selected=false]:hidden" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"> + <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" /> + </svg> + </label> + } + + {config.supported_tan_channels.indexOf(TanChannel.SMS) === -1 ? undefined : + <label onClick={() => { + if (!resultAccount.body.contact_data?.phone) return; + form.channel = TanChannel.SMS + updateForm(structuredClone(form)) + }} data-disabled={!resultAccount.body.contact_data?.phone} data-selected={form.channel === TanChannel.SMS} + class="relative flex data-[disabled=false]:cursor-pointer rounded-lg border data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"> + <input type="radio" name="channel" value="Existing Customers" class="sr-only" /> + <span class="flex flex-1"> + <span class="flex flex-col"> + <span id="project-type-1-label" class="block text-sm font-medium text-gray-900"> + <i18n.Translate>SMS</i18n.Translate> + </span> + {!resultAccount.body.contact_data?.phone && i18n.str`add a phone number in your profile to enable this option`} + </span> </span> - {!resultAccount.body.contact_data?.phone && i18n.str`add a phone number in your profile to enable this option`} - </span> - </span> - <svg data-selected={form.channel === TanChannel.SMS} class="h-5 w-5 text-indigo-600 data-[selected=false]:hidden" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"> - <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" /> - </svg> - </label> - + <svg data-selected={form.channel === TanChannel.SMS} class="h-5 w-5 text-indigo-600 data-[selected=false]:hidden" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"> + <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" /> + </svg> + </label> + } + </div> </div> - </div> - </div> + </div> + } </div> </div> diff --git a/packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx b/packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx @@ -19,6 +19,10 @@ import { TranslatedString } from "@gnu-taler/taler-util"; import { + Attention, + Loading, + LocalNotificationBanner, + ShowInputErrorLabel, useLocalNotification, useTranslationContext } from "@gnu-taler/web-util/browser"; @@ -26,22 +30,17 @@ import { format } from "date-fns"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; import { mutate } from "swr"; -import { Attention } from "@gnu-taler/web-util/browser"; -import { ErrorLoading } from "@gnu-taler/web-util/browser"; -import { Loading } from "@gnu-taler/web-util/browser"; -import { ShowInputErrorLabel } from "@gnu-taler/web-util/browser"; +import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js"; import { useBankCoreApiContext } from "../../context/config.js"; import { useBackendState } from "../../hooks/backend.js"; import { useCashoutDetails, useConversionInfo } from "../../hooks/circuit.js"; import { - undefinedIfEmpty, - withRuntimeErrorHandling + undefinedIfEmpty } from "../../utils.js"; -import { assertUnreachable } from "../WithdrawalOperationPage.js"; -import { LocalNotificationBanner } from "@gnu-taler/web-util/browser"; import { RenderAmount } from "../PaytoWireTransferForm.js"; +import { assertUnreachable } from "../WithdrawalOperationPage.js"; interface Props { id: string; @@ -70,7 +69,7 @@ export function ShowCashoutDetails({ return <Loading /> } if (result instanceof TalerError) { - return <ErrorLoading error={result} /> + return <ErrorLoadingWithDebug error={result} /> } if (result.type === "fail") { switch (result.case) { @@ -86,7 +85,7 @@ export function ShowCashoutDetails({ } if (info instanceof TalerError) { - return <ErrorLoading error={info} /> + return <ErrorLoadingWithDebug error={info} /> } const errors = undefinedIfEmpty({ diff --git a/packages/demobank-ui/src/settings.ts b/packages/demobank-ui/src/settings.ts @@ -64,13 +64,22 @@ const codecForBankUISettings = (): Codec<BankUiSettings> => .property("topNavSites", codecOptional(codecForMap(codecForString()))) .build("BankUiSettings"); +function removeUndefineField(obj: any): object { + return Object.keys(obj).reduce((prev, cur) => { + if (typeof prev[cur] === "undefined") { + delete prev[cur] + } + return prev + }, obj) +} + export function fetchSettings(listener: (s: BankUiSettings) => void): void { fetch("./settings.json") .then(resp => resp.json()) .then(json => codecForBankUISettings().decode(json)) .then(result => listener({ ...defaultSettings, - ...result, + ...removeUndefineField(result), })) .catch(e => { console.log("failed to fetch settings", e) diff --git a/packages/demobank-ui/src/stories.test.ts b/packages/demobank-ui/src/stories.test.ts @@ -18,7 +18,7 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { AccessToken, TalerCorebankApi, setupI18n } from "@gnu-taler/taler-util"; +import { AccessToken, AmountString, TalerCorebankApi, setupI18n } from "@gnu-taler/taler-util"; import { parseGroupImport } from "@gnu-taler/web-util/browser"; import * as tests from "@gnu-taler/web-util/testing"; import * as components from "./components/index.examples.js"; @@ -64,8 +64,11 @@ function DefaultTestingContext({ const cfg: TalerCorebankApi.Config = { name: "libeufin-bank", allow_deletions: true, + supported_tan_channels: [], allow_registrations: true, allow_conversion: true, + allow_edit_cashout_payto_uri: false, + allow_edit_name: false, currency: "ASR", currency_specification: { name: "ARS", @@ -74,6 +77,7 @@ function DefaultTestingContext({ num_fractional_normal_digits: 2, num_fractional_trailing_zero_digits: 2, }, + default_debit_threshold: "ARS:10" as AmountString, version: "1:0:0", } const ctx2 = create(BankCoreApiProviderTesting, { diff --git a/packages/demobank-ui/src/utils.ts b/packages/demobank-ui/src/utils.ts @@ -14,7 +14,7 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { HttpStatusCode, TalerError, TalerErrorCode, TranslatedString } from "@gnu-taler/taler-util"; +import { AmountString, HttpStatusCode, PaytoString, TalerError, TalerErrorCode, TranslatedString } from "@gnu-taler/taler-util"; import { ErrorNotification, ErrorType, @@ -62,17 +62,36 @@ export type PartialButDefined<T> = { [P in keyof T]: T[P] | undefined; }; -export type WithIntermediate<Type extends object> = { - [prop in keyof Type]: Type[prop] extends object +/** + * every non-map field can be undefined + */ +export type WithIntermediate<Type> = { + [prop in keyof Type]: + Type[prop] extends PaytoString ? Type[prop] | undefined : + Type[prop] extends AmountString ? Type[prop] | undefined : + Type[prop] extends TranslatedString ? Type[prop] | undefined : + Type[prop] extends object ? WithIntermediate<Type[prop]> : Type[prop] | undefined; }; -export type RecursivePartial<T> = { - [P in keyof T]?: T[P] extends (infer U)[] +export type RecursivePartial<Type> = { + [P in keyof Type]?: Type[P] extends (infer U)[] ? RecursivePartial<U>[] - : T[P] extends object - ? RecursivePartial<T[P]> - : T[P]; + : Type[P] extends object + ? RecursivePartial<Type[P]> + : Type[P]; +}; +export type ErrorMessageMappingFor<Type> = { + [prop in keyof Type]+?: + //enumerate known object + Exclude<Type[prop],undefined> extends PaytoString ? TranslatedString : + Exclude<Type[prop],undefined> extends AmountString ? TranslatedString : + Exclude<Type[prop],undefined> extends TranslatedString ? TranslatedString : + // arrays: every element + Exclude<Type[prop],undefined> extends (infer U)[] ? ErrorMessageMappingFor<U>[] : + // map: every field + Exclude<Type[prop],undefined> extends object ? ErrorMessageMappingFor<Type[prop]> + : TranslatedString; }; export enum TanChannel { @@ -108,12 +127,12 @@ export async function withRuntimeErrorHandling<T>(i18n: Translator, cb: () => Pr ? error.message : JSON.stringify(error)) as TranslatedString ) - } + } } } -export function buildRequestErrorMessage( i18n: Translator, cause: TalerError): ErrorNotification { +export function buildRequestErrorMessage(i18n: Translator, cause: TalerError): ErrorNotification { let result: ErrorNotification; switch (cause.errorDetail.code) { case TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT: { @@ -337,7 +356,7 @@ export const COUNTRY_TABLE = { export function validateIBAN( iban: string, i18n: ReturnType<typeof useTranslationContext>["i18n"], -): string | undefined { +): TranslatedString | undefined { // Check total length if (iban.length < 4) return i18n.str`IBAN numbers usually have more that 4 digits`; diff --git a/packages/idb-bridge/.gitignore b/packages/idb-bridge/.gitignore @@ -1 +1,2 @@ /build +mytestdb.sqlite3 diff --git a/packages/idb-bridge/package.json b/packages/idb-bridge/package.json @@ -25,19 +25,19 @@ } }, "devDependencies": { - "@types/better-sqlite3": "^7.6.4", + "@types/better-sqlite3": "^7.6.8", "@types/node": "^20.4.1", - "ava": "^5.3.1", - "prettier": "^2.8.8", - "typescript": "^5.2.2" + "ava": "^6.0.1", + "prettier": "^3.1.1", + "typescript": "^5.3.3" }, "dependencies": { - "tslib": "^2.6.0" + "tslib": "^2.6.2" }, "ava": { "failFast": true }, "optionalDependencies": { - "better-sqlite3": "^8.4.0" + "better-sqlite3": "^9.2.2" } } diff --git a/packages/merchant-backend-ui/package.json b/packages/merchant-backend-ui/package.json @@ -1,6 +1,6 @@ { "private": true, - "name": "@gnu-taler/merchant-backend", + "name": "@gnu-taler/merchant-backend-ui", "version": "0.0.5", "license": "AGPL-3.0-or-later", "scripts": { @@ -62,7 +62,7 @@ "preact-render-to-string": "^5.1.19", "sirv-cli": "^1.0.11", "ts-node": "^10.9.1", - "tslib": "2.5.3", - "typescript": "5.2.2" + "tslib": "2.6.2", + "typescript": "5.3.3" } } diff --git a/packages/merchant-backend-ui/src/declaration.d.ts b/packages/merchant-backend-ui/src/declaration.d.ts @@ -50,7 +50,9 @@ interface WithId { type Amount = string; type UUID = string; type Integer = number; - +type TalerProtocolTimestamp = { + t_s: number | "never" +} export namespace ExchangeBackend { interface WireResponse { diff --git a/packages/merchant-backend-ui/src/pages/OfferRefund.tsx b/packages/merchant-backend-ui/src/pages/OfferRefund.tsx @@ -61,6 +61,8 @@ function Head({ order_summary }: { order_summary?: string }): VNode { export function OfferRefund({ refundURI, qr_code, order_status_url }: Props): VNode { useEffect(() => { + const longpollDelayMs = 60 * 1000; + const delayMs = 500; let checkUrl: URL; try { checkUrl = new URL(order_status_url ? order_status_url : "{{& order_status_url }}"); @@ -68,7 +70,7 @@ export function OfferRefund({ refundURI, qr_code, order_status_url }: Props): VN return; } checkUrl.searchParams.set("await_refund_obtained", "yes"); - const delayMs = 500; + checkUrl.searchParams.set("timeout_ms", longpollDelayMs.toString()); function check() { let retried = false; function retryOnce() { diff --git a/packages/merchant-backend-ui/src/pages/OfferTip.tsx b/packages/merchant-backend-ui/src/pages/OfferTip.tsx @@ -62,14 +62,16 @@ export function Head(): VNode { export function OfferTip({ tipURI, qr_code, tip_status_url }: Props): VNode { useEffect(() => { + const longpollDelayMs = 60 * 1000; + const delayMs = 500; let checkUrl: URL; try { checkUrl = new URL(tip_status_url ? tip_status_url : "{{& tip_status_url }}"); } catch (e) { return; } + checkUrl.searchParams.set("timeout_ms", longpollDelayMs.toString()); - const delayMs = 500; function check() { let retried = false; function retryOnce() { diff --git a/packages/merchant-backend-ui/src/pages/RequestPayment.tsx b/packages/merchant-backend-ui/src/pages/RequestPayment.tsx @@ -82,6 +82,7 @@ export function RequestPayment({ return; } checkUrl.searchParams.set("timeout_s", longpollDelayMs.toString()); + const delayMs = 500; function check() { let retried = false; function retryOnce() { @@ -123,20 +124,20 @@ export function RequestPayment({ console.error("could not parse response:", e); } } - setTimeout(retryOnce, 500); + setTimeout(retryOnce, delayMs); } }; req.onerror = function () { - setTimeout(retryOnce, 500); + setTimeout(retryOnce, delayMs); }; req.ontimeout = function () { - setTimeout(retryOnce, 500); + setTimeout(retryOnce, delayMs); }; req.timeout = longpollDelayMs; req.open("GET", checkUrl.href); req.send(); } - setTimeout(check, 500); + setTimeout(check, delayMs); }); return ( <Page> diff --git a/packages/merchant-backend-ui/src/pages/ShowOrderDetails.examples.ts b/packages/merchant-backend-ui/src/pages/ShowOrderDetails.examples.ts @@ -28,7 +28,7 @@ const defaultContractTerms: MerchantBackend.ContractTerms = { amount: 'USD:10', summary: 'this is a short summary', pay_deadline: { - t_s: new Date().getTime() + 6 * 24 * 60 * 60 * 1000 + t_s: Math.round(new Date().getTime() / 1000) + 6 * 24 * 60 * 60 }, merchant: { name: 'the merchant (inc)', @@ -48,7 +48,7 @@ const defaultContractTerms: MerchantBackend.ContractTerms = { wire_fee_amortization: 1, products: [], timestamp: { - t_s: new Date().getTime() + t_s: Math.round(new Date().getTime() / 1000) }, auditors: [], exchanges: [], @@ -57,18 +57,18 @@ const defaultContractTerms: MerchantBackend.ContractTerms = { merchant_pub: 'QWEASDQWEASD', nonce: 'NONCE', refund_deadline: { - t_s: new Date().getTime() + 6 * 24 * 60 * 60 * 1000 + t_s: Math.round(new Date().getTime() / 1000) + 6 * 24 * 60 * 60 }, wire_method: 'x-taler-bank', wire_transfer_deadline: { - t_s: new Date().getTime() + 3 * 24 * 60 * 60 * 1000 + t_s: Math.round(new Date().getTime() / 1000) + 3 * 24 * 60 * 60 }, }; -const inSixDays = new Date().getTime() + 6 * 24 * 60 * 60 * 1000 -const in10Minutes = new Date().getTime() + 10 * 60 * 1000 -const in15Minutes = new Date().getTime() + 15 * 60 * 1000 -const in20Minutes = new Date().getTime() + 20 * 60 * 1000 +const inSixDays = Math.round(new Date().getTime() / 1000) + 6 * 24 * 60 * 60 +const in10Minutes = Math.round(new Date().getTime() / 1000) + 10 * 60 +const in15Minutes = Math.round(new Date().getTime() / 1000) + 15 * 60 +const in20Minutes = Math.round(new Date().getTime() / 1000) + 20 * 60 export const exampleData: { [name: string]: Props } = { Simplest: { diff --git a/packages/merchant-backoffice-ui/package.json b/packages/merchant-backoffice-ui/package.json @@ -74,8 +74,8 @@ "preact-render-to-string": "^5.2.6", "sass": "1.56.1", "source-map-support": "^0.5.21", - "typedoc": "^0.25.1", - "typescript": "5.2.2" + "typedoc": "^0.25.4", + "typescript": "5.3.3" }, "pogen": { "domain": "taler-merchant-backoffice" diff --git a/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx b/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx @@ -276,6 +276,7 @@ export function InputPaytoForm<T>({ label={i18n.str`Account type`} tooltip={i18n.str`Method to use for wire transfer`} values={targets} + readonly={readonly} toStr={(v) => (v === noTargetValue ? i18n.str`Choose one...` : v)} /> @@ -284,11 +285,13 @@ export function InputPaytoForm<T>({ <Input<Entity> name="path1" label={i18n.str`Routing`} + readonly={readonly} tooltip={i18n.str`Routing number.`} /> <Input<Entity> name="path2" label={i18n.str`Account`} + readonly={readonly} tooltip={i18n.str`Account number.`} /> </Fragment> @@ -298,6 +301,7 @@ export function InputPaytoForm<T>({ <Input<Entity> name="path1" label={i18n.str`Code`} + readonly={readonly} tooltip={i18n.str`Business Identifier Code.`} /> </Fragment> @@ -308,6 +312,7 @@ export function InputPaytoForm<T>({ name="path1" label={i18n.str`IBAN`} tooltip={i18n.str`International Bank Account Number.`} + readonly={readonly} placeholder="DE1231231231" inputExtra={{ style: { textTransform: "uppercase" } }} /> @@ -317,6 +322,7 @@ export function InputPaytoForm<T>({ <Fragment> <Input<Entity> name="path1" + readonly={readonly} label={i18n.str`Account`} tooltip={i18n.str`Unified Payment Interface.`} /> @@ -326,6 +332,7 @@ export function InputPaytoForm<T>({ <Fragment> <Input<Entity> name="path1" + readonly={readonly} label={i18n.str`Address`} tooltip={i18n.str`Bitcoin protocol.`} /> @@ -335,6 +342,7 @@ export function InputPaytoForm<T>({ <Fragment> <Input<Entity> name="path1" + readonly={readonly} label={i18n.str`Address`} tooltip={i18n.str`Ethereum protocol.`} /> @@ -344,6 +352,7 @@ export function InputPaytoForm<T>({ <Fragment> <Input<Entity> name="path1" + readonly={readonly} label={i18n.str`Address`} tooltip={i18n.str`Interledger protocol.`} /> @@ -354,11 +363,13 @@ export function InputPaytoForm<T>({ <Fragment> <Input<Entity> name="path1" + readonly={readonly} label={i18n.str`Host`} tooltip={i18n.str`Bank host.`} /> <Input<Entity> name="path2" + readonly={readonly} label={i18n.str`Account`} tooltip={i18n.str`Bank account.`} /> @@ -372,6 +383,7 @@ export function InputPaytoForm<T>({ <Fragment> <Input name="params.receiver-name" + readonly={readonly} label={i18n.str`Owner's name`} tooltip={i18n.str`Legal name of the person holding the account.`} /> diff --git a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx @@ -228,14 +228,6 @@ export function Sidebar({ <li> <div> <span style={{ width: "3rem" }} class="icon"> - <i class="mdi mdi-currency-eur" /> - </span> - <span class="menu-item-label">{config.currency}</span> - </div> - </li> - <li> - <div> - <span style={{ width: "3rem" }} class="icon"> <i class="mdi mdi-web" /> </span> <span class="menu-item-label"> diff --git a/packages/merchant-backoffice-ui/src/i18n/de.po b/packages/merchant-backoffice-ui/src/i18n/de.po @@ -17,7 +17,7 @@ msgstr "" "Project-Id-Version: Taler Wallet\n" "Report-Msgid-Bugs-To: taler@gnu.org\n" "POT-Creation-Date: 2016-11-23 00:00+0100\n" -"PO-Revision-Date: 2023-08-15 07:28+0000\n" +"PO-Revision-Date: 2023-12-04 13:44+0000\n" "Last-Translator: Stefan Kügel <skuegel@web.de>\n" "Language-Team: German <https://weblate.taler.net/projects/gnu-taler/" "merchant-backoffice/de/>\n" @@ -26,7 +26,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.13.1\n" +"X-Generator: Weblate 5.2.1\n" #: src/components/modal/index.tsx:71 #, c-format @@ -1203,7 +1203,7 @@ msgstr "" #: src/paths/instance/orders/details/DetailPage.tsx:767 #, c-format msgid "Back" -msgstr "" +msgstr "Zurück" #: src/paths/instance/orders/details/index.tsx:79 #, c-format diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/UpdatePage.tsx @@ -20,7 +20,7 @@ */ import { useTranslationContext } from "@gnu-taler/web-util/browser"; -import { h, VNode } from "preact"; +import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { AsyncButton } from "../../../../components/exception/AsyncButton.js"; import { @@ -29,20 +29,41 @@ import { } from "../../../../components/form/FormProvider.js"; import { Input } from "../../../../components/form/Input.js"; import { MerchantBackend, WithId } from "../../../../declaration.js"; +import { InputSelector } from "../../../../components/form/InputSelector.js"; +import { InputPaytoForm } from "../../../../components/form/InputPaytoForm.js"; +import { undefinedIfEmpty } from "../../../../utils/table.js"; -type Entity = MerchantBackend.BankAccounts.AccountPatchDetails & WithId; +type Entity = MerchantBackend.BankAccounts.BankAccountEntry + & WithId; +const accountAuthType = ["unedit", "none", "basic"]; interface Props { - onUpdate: (d: Entity) => Promise<void>; + onUpdate: (d: MerchantBackend.BankAccounts.AccountPatchDetails) => Promise<void>; onBack?: () => void; account: Entity; } + + export function UpdatePage({ account, onUpdate, onBack }: Props): VNode { const { i18n } = useTranslationContext(); - const [state, setState] = useState<Partial<Entity>>(account); + const [state, setState] = useState<Partial<MerchantBackend.BankAccounts.AccountPatchDetails>>(account); + + const errors: FormErrors<MerchantBackend.BankAccounts.AccountPatchDetails> = { + credit_facade_url: !state.credit_facade_url ? i18n.str`required` : !isValidURL(state.credit_facade_url) ? i18n.str`invalid url` : undefined, + credit_facade_credentials: undefinedIfEmpty({ - const errors: FormErrors<Entity> = { + username: state.credit_facade_credentials?.type !== "basic" ? undefined + : !state.credit_facade_credentials.username ? i18n.str`required` : undefined, + + password: state.credit_facade_credentials?.type !== "basic" ? undefined + : !state.credit_facade_credentials.password ? i18n.str`required` : undefined, + + repeatPassword: state.credit_facade_credentials?.type !== "basic" ? undefined + : !(state.credit_facade_credentials as any).repeatPassword ? i18n.str`required` : + (state.credit_facade_credentials as any).repeatPassword !== state.credit_facade_credentials.password ? i18n.str`doesnt match` + : undefined, + }), }; const hasErrors = Object.keys(errors).some( @@ -51,7 +72,20 @@ export function UpdatePage({ account, onUpdate, onBack }: Props): VNode { const submitForm = () => { if (hasErrors) return Promise.reject(); - return onUpdate(state as any); + + const creds: typeof state.credit_facade_credentials = + state.credit_facade_credentials?.type === "basic" ? { + type: "basic", + password: state.credit_facade_credentials.password, + username: state.credit_facade_credentials.username, + } : state.credit_facade_credentials?.type === "none" ? { + type: "none" + } : undefined; + + return onUpdate({ + credit_facade_credentials: creds, + credit_facade_url: state.credit_facade_url, + }); }; return ( @@ -63,7 +97,7 @@ export function UpdatePage({ account, onUpdate, onBack }: Props): VNode { <div class="level-left"> <div class="level-item"> <span class="is-size-4"> - Account: <b>{account.id}</b> + Account: <b>{account.id.substring(0, 8)}...</b> </span> </div> </div> @@ -80,11 +114,49 @@ export function UpdatePage({ account, onUpdate, onBack }: Props): VNode { valueHandler={setState} errors={errors} > + <InputPaytoForm<Entity> + name="payto_uri" + label={i18n.str`Account`} + readonly + /> <Input<Entity> name="credit_facade_url" - label={i18n.str`Description`} - tooltip={i18n.str`dddd`} + label={i18n.str`Account info URL`} + help="https://bank.com" + expand + tooltip={i18n.str`From where the merchant can download information about incoming wire transfers to this account`} + /> + <InputSelector + name="credit_facade_credentials.type" + label={i18n.str`Auth type`} + tooltip={i18n.str`Choose the authentication type for the account info URL`} + values={accountAuthType} + toStr={(str) => { + if (str === "none") return "Without authentication"; + if (str === "basic") return "With authentication"; + return "Do not change" + }} /> + {state.credit_facade_credentials?.type === "basic" ? ( + <Fragment> + <Input + name="credit_facade_credentials.username" + label={i18n.str`Username`} + tooltip={i18n.str`Username to access the account information.`} + /> + <Input + name="credit_facade_credentials.password" + inputType="password" + label={i18n.str`Password`} + tooltip={i18n.str`Password to access the account information.`} + /> + <Input + name="credit_facade_credentials.repeatPassword" + inputType="password" + label={i18n.str`Repeat password`} + /> + </Fragment> + ) : undefined} </FormProvider> <div class="buttons is-right mt-5"> @@ -112,3 +184,12 @@ export function UpdatePage({ account, onUpdate, onBack }: Props): VNode { </div> ); } + +function isValidURL(s: string): boolean { + try { + const u = new URL(s) + return true; + } catch (e) { + return false; + } +} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/UpdatePage.tsx @@ -89,7 +89,7 @@ export function UpdatePage({ device, onUpdate, onBack }: Props): VNode { <Input<Entity> name="otp_device_description" label={i18n.str`Description`} - tooltip={i18n.str`dddd`} + tooltip={i18n.str`Useful to identify the device physically`} /> <InputSelector<Entity> name="otp_algorithm" diff --git a/packages/merchant-backoffice-ui/src/paths/instance/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/update/UpdatePage.tsx @@ -66,13 +66,6 @@ function convert( return { ...defaults, ...rest }; } -function getTokenValuePart(t?: string): string | undefined { - if (!t) return t; - const match = /secret-token:(.*)/.exec(t); - if (!match || !match[1]) return undefined; - return match[1]; -} - export function UpdatePage({ onUpdate, selected, diff --git a/packages/pogen/example/proj1/tsconfig.json b/packages/pogen/example/proj1/tsconfig.json @@ -4,7 +4,7 @@ "composite": true, "declaration": true, "declarationMap": false, - "target": "ES6", + "target": "ES2020", "module": "ESNext", "moduleResolution": "node", "sourceMap": true, diff --git a/packages/pogen/package.json b/packages/pogen/package.json @@ -12,10 +12,10 @@ }, "devDependencies": { "po2json": "^0.4.5", - "typescript": "^5.2.2" + "typescript": "^5.3.3" }, "dependencies": { "@types/node": "^18.11.17", - "glob": "^7.2.0" + "glob": "^10.3.10" } } diff --git a/packages/pogen/tsconfig.json b/packages/pogen/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "module": "commonjs", - "target": "es5", + "target": "ES2020", "noImplicitAny": false, "outDir": "lib", "incremental": true, diff --git a/packages/taler-harness/Makefile b/packages/taler-harness/Makefile @@ -41,3 +41,7 @@ install: $(MAKE) deps $(MAKE) install-nodeps endif + +.PHONY: deb +deb: + dpkg-buildpackage -rfakeroot -b -uc -us diff --git a/packages/taler-harness/debian/changelog b/packages/taler-harness/debian/changelog @@ -1,3 +1,15 @@ +taler-harness (0.9.3-1) unstable; urgency=low + + * Misc bugfixes. + + -- Christian Grothoff <grothoff@gnu.org> Tue, 13 Dec 2023 18:53:15 -0700 + +taler-harness (0.9.3) unstable; urgency=low + + * First release for GNU Taler v0.9.3. + + -- Christian Grothoff <grothoff@gnu.org> Wed, 29 Nov 2023 08:53:15 -0800 + taler-harness (0.9.2-2) unstable; urgency=low * Release with various Debian package fixes. diff --git a/packages/taler-harness/debian/rules b/packages/taler-harness/debian/rules @@ -1,32 +1,15 @@ #!/usr/bin/make -f -include /usr/share/dpkg/default.mk -TALER_HARNESS_HOME = /usr/share/taler-harness +%: + dh ${@} -build: build-arch build-indep -build-arch: - true -build-indep: - true -override_dh_auto_install: - dh_install bin/taler-harness.mjs $(TALER_HARNESS_HOME)/node_modules/taler-harness/bin - dh_install dist/taler-harness-bundled.cjs $(TALER_HARNESS_HOME)/node_modules/taler-harness/dist - dh_install dist/taler-harness-bundled.cjs.map $(TALER_HARNESS_HOME)/node_modules/taler-harness/dist - dh_link $(TALER_HARNESS_HOME)/node_modules/taler-harness/bin/taler-harness.mjs /usr/bin/taler-harness +# Override because our configure doesn't like extra arguments. +override_dh_auto_configure: + ./configure --prefix=/usr override_dh_builddeb: dh_builddeb -- -Zgzip -binary: - dh $@ -binary-arch: - dh $@ -binary-indep: - dh $@ - -clean: - true - # Override this step because it's very slow and likely # unnecessary for us. override_dh_strip_nondeterminism: diff --git a/packages/taler-harness/package.json b/packages/taler-harness/package.json @@ -33,13 +33,13 @@ ], "devDependencies": { "@types/node": "^18.11.17", - "esbuild": "^0.17.7", - "prettier": "^2.8.8", - "typescript": "^5.2.2" + "esbuild": "^0.19.9", + "prettier": "^3.1.1", + "typescript": "^5.3.3" }, "dependencies": { "@gnu-taler/taler-util": "workspace:*", "@gnu-taler/taler-wallet-core": "workspace:*", - "tslib": "^2.5.3" + "tslib": "^2.6.2" } } \ No newline at end of file diff --git a/packages/taler-harness/src/bench2.ts b/packages/taler-harness/src/bench2.ts @@ -28,7 +28,7 @@ import { import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; import { checkReserve, - createFakebankReserve, + createTestingReserve, CryptoDispatcher, depositCoin, downloadExchangeInfo, @@ -72,10 +72,10 @@ export async function runBench2(configJson: any): Promise<void> { console.log("creating fakebank reserve"); - await createFakebankReserve({ + await createTestingReserve({ amount: `${curr}:${reserveAmount}`, exchangeInfo, - fakebankBaseUrl: benchConf.bank, + corebankApiBaseUrl: benchConf.bank, http, reservePub: reserveKeyPair.pub, }); diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts @@ -371,7 +371,7 @@ export class GlobalTestState { }); proc.on("exit", (code, signal) => { if (code == 0 && signal == null) { - logger.info(`process ${logName} exited with success`); + logger.trace(`process ${logName} exited with success`); } else { logger.warn(`process ${logName} exited ${j2s({ code, signal })}`); } @@ -930,11 +930,11 @@ export class ExchangeService implements ExchangeServiceInterface { private exchangeBankAccounts: HarnessExchangeBankAccount[] = []; - setTimetravel(t: number | undefined): void { + setTimetravel(tMs: number | undefined): void { if (this.isRunning()) { throw Error("can't set time travel while the exchange is running"); } - this.currentTimetravelOffsetMs = t; + this.currentTimetravelOffsetMs = tMs; } private get timetravelArg(): string | undefined { diff --git a/packages/taler-harness/src/http-client/bank-core.ts b/packages/taler-harness/src/http-client/bank-core.ts @@ -1,978 +0,0 @@ -import { AccessToken, AmountJson, Amounts, TalerCoreBankHttpClient, TalerCorebankApi, TalerRevenueHttpClient, TalerWireGatewayApi, TalerWireGatewayHttpClient, TestForApi, buildPayto, encodeCrock, failOrThrow, getRandomBytes, parsePaytoUri, stringifyPaytoUri, succeedOrThrow } from "@gnu-taler/taler-util" - - - -export function createTestForBankCore(api: TalerCoreBankHttpClient, adminToken: AccessToken): TestForApi<TalerCoreBankHttpClient> { - return { - test_abortCashoutById: { - success: undefined, - "already-confirmed": undefined, - "cashout-not-supported": undefined, - "not-found": undefined, - }, - test_createCashout: { - "account-not-found": undefined, - "incorrect-exchange-rate": undefined, - "no-contact-info": undefined, - "no-enough-balance": undefined, - "cashout-not-supported": undefined, - "request-already-used": undefined, - "tan-failed": undefined, - success: undefined, - }, - test_confirmCashoutById: { - "already-aborted": undefined, - "incorrect-exchange-rate": undefined, - "no-cashout-payto": undefined, - "no-enough-balance": undefined, - "invalid-code": undefined, - "too-many-attempts": undefined, - "cashout-not-supported": undefined, - "not-found": undefined, - success: undefined, - }, - test_getAccountCashouts: { - "cashout-not-supported": undefined, - "account-not-found": undefined, - success: undefined, - }, - test_getCashoutById: { - "cashout-not-supported": undefined, - success: undefined, - "not-found": undefined, - }, - test_getGlobalCashouts: { - "cashout-not-supported": undefined, - success: undefined, - }, - test_abortWithdrawalById: { - "invalid-id": async () => { - await failOrThrow("invalid-id", () => - api.abortWithdrawalById("invalid") - ) - }, - "not-found": async () => { - await failOrThrow("not-found", () => - api.abortWithdrawalById("11111111-1111-1111-1111-111111111111") - ) - }, - "previously-confirmed": async () => { - const { username: exchangeUser, token: exchangeToken } = await createRandomTestUser(api, adminToken, { is_taler_exchange: true }) - const { username, token } = await createRandomTestUser(api, adminToken) - - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - const exchangeInfo = await succeedOrThrow(() => - api.getAccount({ username: exchangeUser, token: exchangeToken }) - ) - - const { withdrawal_id } = await succeedOrThrow(() => - api.createWithdrawal({ username, token }, { - amount: userInfo.balance.amount - }) - ) - - await succeedOrThrow(() => - api.getIntegrationAPI().completeWithdrawalOperationById(withdrawal_id, { - reserve_pub: encodeCrock(getRandomBytes(32)), - selected_exchange: exchangeInfo.payto_uri, - }) - ) - await succeedOrThrow(() => - api.confirmWithdrawalById(withdrawal_id) - ) - await failOrThrow("previously-confirmed", () => - api.abortWithdrawalById(withdrawal_id) - ) - }, - success: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - - const { withdrawal_id: firstWithdrawal } = await succeedOrThrow(() => - api.createWithdrawal({ username, token }, { - amount: userInfo.balance.amount - }) - ) - - await succeedOrThrow(() => - api.abortWithdrawalById(firstWithdrawal) - ) - }, - }, - test_confirmWithdrawalById: { - "insufficient-funds": async () => { - - }, - "invalid-id": async () => { - await failOrThrow("invalid-id", () => - api.confirmWithdrawalById("invalid") - ) - }, - "no-exchange-or-reserve-selected": async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - - const { withdrawal_id } = await succeedOrThrow(() => - api.createWithdrawal({ username, token }, { - amount: userInfo.balance.amount - }) - ) - - await failOrThrow("no-exchange-or-reserve-selected", () => - api.confirmWithdrawalById(withdrawal_id) - ) - }, - "not-found": async () => { - await failOrThrow("not-found", () => - api.confirmWithdrawalById("11111111-1111-1111-1111-111111111111") - ) - }, - "previously-aborted": async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - const { withdrawal_id } = await succeedOrThrow(() => - api.createWithdrawal({ username, token }, { - amount: userInfo.balance.amount - }) - ) - - await succeedOrThrow(() => - api.abortWithdrawalById(withdrawal_id) - ) - await failOrThrow("previously-aborted", () => - api.confirmWithdrawalById(withdrawal_id) - ) - }, - success: async () => { - const { username: exchangeUser, token: exchangeToken } = await createRandomTestUser(api, adminToken, { is_taler_exchange: true }) - const { username, token } = await createRandomTestUser(api, adminToken) - - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - const exchangeInfo = await succeedOrThrow(() => - api.getAccount({ username: exchangeUser, token: exchangeToken }) - ) - - const { withdrawal_id } = await succeedOrThrow(() => - api.createWithdrawal({ username, token }, { - amount: userInfo.balance.amount - }) - ) - - await succeedOrThrow(() => - api.getIntegrationAPI().completeWithdrawalOperationById(withdrawal_id, { - reserve_pub: encodeCrock(getRandomBytes(32)), - selected_exchange: exchangeInfo.payto_uri, - }) - ) - - await succeedOrThrow(() => - api.confirmWithdrawalById(withdrawal_id) - ) - - }, - }, - test_createAccount: { - "insufficient-funds": undefined, - "payto-already-exists": async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - - const anotherUsername = "harness-" + encodeCrock(getRandomBytes(10)).toLowerCase(); - await failOrThrow("payto-already-exists", () => - api.createAccount(adminToken, { - name: anotherUsername, - username: anotherUsername, - password: "123", - internal_payto_uri: userInfo.payto_uri, - }) - ); - - }, - "username-reserved": async () => { - await failOrThrow("username-reserved", () => - api.createAccount(adminToken, { - name: "admin", - username: "admin", password: "123" - }) - ) - }, - "username-already-exists": async () => { - const username = "harness-" + encodeCrock(getRandomBytes(10)).toLowerCase(); - await succeedOrThrow(() => - api.createAccount(adminToken, { - name: username, - username, password: "123" - }) - ) - - await failOrThrow("username-already-exists", () => - api.createAccount(adminToken, { - name: username, - username, password: "123" - }) - ); - }, - "invalid-phone-or-email": async () => { - const username = "harness-" + encodeCrock(getRandomBytes(10)).toLowerCase(); - await failOrThrow("invalid-input", () => - api.createAccount(adminToken, { - name: username, - username, password: "123", - challenge_contact_data: { - email: "invalid email", - phone: "invalid phone", - } - }) - ) - }, - success: async () => { - const username = "harness-" + encodeCrock(getRandomBytes(10)).toLowerCase(); - - await succeedOrThrow(() => - api.createAccount(adminToken, { - name: username, - username, password: "123" - }) - ) - }, - unauthorized: async () => { - const username = "harness-" + encodeCrock(getRandomBytes(10)).toLowerCase(); - - await succeedOrThrow(() => - api.createAccount(adminToken, { - name: username, - username, password: "123" - }) - ) - - const { access_token } = await succeedOrThrow(() => - api.getAuthenticationAPI(username).createAccessToken("123", { - scope: "readwrite" - }) - ) - - const anotherUser = "harness-" + encodeCrock(getRandomBytes(10)).toLowerCase(); - await failOrThrow("unauthorized", () => - api.createAccount(access_token, { - name: anotherUser, - username: anotherUser, password: "123" - }) - ) - - }, - - }, - test_createTransaction: { - "creditor-not-found": async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - - const notFoundAccount = buildPayto("iban", "DE1231231231", undefined) - notFoundAccount.params["message"] = "not-found" - await failOrThrow("creditor-not-found", () => - api.createTransaction({ username, token }, { - payto_uri: stringifyPaytoUri(notFoundAccount), - amount: userInfo.balance.amount - }) - ) - }, - "creditor-same": async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - const account = parsePaytoUri(userInfo.payto_uri)! - account.params["message"] = "myaccount" - - await failOrThrow("creditor-same", () => - api.createTransaction({ username, token }, { - payto_uri: stringifyPaytoUri(account), - amount: userInfo.balance.amount - }) - ) - - }, - "insufficient-funds": async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - const { username: otherUser, token: otherToken } = await createRandomTestUser(api, adminToken) - - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - const otherInfo = await succeedOrThrow(() => - api.getAccount({ username: otherUser, token: otherToken }) - ) - const otherAccount = parsePaytoUri(otherInfo.payto_uri)! - otherAccount.params["message"] = "all" - - await failOrThrow("insufficient-funds", () => - api.createTransaction({ username, token }, { - payto_uri: stringifyPaytoUri(otherAccount), - amount: Amounts.stringify(Amounts.mult(userInfo.balance.amount, 20).amount) - }) - ) - }, - "not-found": async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - const { username: otherUser, token: otherToken } = await createRandomTestUser(api, adminToken) - - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - const otherInfo = await succeedOrThrow(() => - api.getAccount({ username: otherUser, token: otherToken }) - ) - const otherAccount = parsePaytoUri(otherInfo.payto_uri)! - otherAccount.params["message"] = "all" - - await succeedOrThrow(() => - api.createTransaction({ username: "notfound", token }, { - payto_uri: stringifyPaytoUri(otherAccount), - amount: userInfo.balance.amount - }) - ) - }, - "invalid-input": async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - const { username: otherUser, token: otherToken } = await createRandomTestUser(api, adminToken) - - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - const otherInfo = await succeedOrThrow(() => - api.getAccount({ username: otherUser, token: otherToken }) - ) - const otherAccount = parsePaytoUri(otherInfo.payto_uri)! - otherAccount.params["message"] = "all" - - //missing amount - await failOrThrow("invalid-input", () => - api.createTransaction({ username, token }, { - payto_uri: stringifyPaytoUri(otherAccount), - // amount: userInfo.balance.amount - }) - ) - //missing subject - await failOrThrow("invalid-input", () => - api.createTransaction({ username, token }, { - payto_uri: otherInfo.payto_uri, - amount: userInfo.balance.amount - }) - ) - - }, - success: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - const { username: otherUser, token: otherToken } = await createRandomTestUser(api, adminToken) - - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - const otherInfo = await succeedOrThrow(() => - api.getAccount({ username: otherUser, token: otherToken }) - ) - const otherAccount = parsePaytoUri(otherInfo.payto_uri)! - otherAccount.params["message"] = "all" - - await succeedOrThrow(() => - api.createTransaction({ username, token }, { - payto_uri: stringifyPaytoUri(otherAccount), - amount: userInfo.balance.amount - }) - ) - - }, - unauthorized: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - const { username: otherUser, token: otherToken } = await createRandomTestUser(api, adminToken) - - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - const otherInfo = await succeedOrThrow(() => - api.getAccount({ username: otherUser, token: otherToken }) - ) - const otherAccount = parsePaytoUri(otherInfo.payto_uri)! - otherAccount.params["message"] = "all" - - await failOrThrow("unauthorized", () => - api.createTransaction({ username, token: "wrongtoken" as AccessToken }, { - payto_uri: stringifyPaytoUri(otherAccount), - amount: userInfo.balance.amount - }) - ) - }, - }, - test_createWithdrawal: { - "account-not-found": async () => { - const userInfo = await succeedOrThrow(() => - api.getAccount({ username: "admin", token: adminToken }) - ) - await succeedOrThrow(() => - api.createWithdrawal({ username: "notfound", token: adminToken }, { - amount: userInfo.balance.amount - }) - ) - - }, - "insufficient-funds": async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - - const balance = Amounts.parseOrThrow(userInfo.balance.amount) - const moreThanBalance = Amounts.stringify(Amounts.mult(balance, 5).amount) - await failOrThrow("insufficient-funds", () => - api.createWithdrawal({ username, token }, { - amount: moreThanBalance - }) - ) - }, - success: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - await succeedOrThrow(() => - api.createWithdrawal({ username, token }, { - amount: userInfo.balance.amount - }) - ) - - }, - unauthorized: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - await failOrThrow("unauthorized", () => - api.createWithdrawal({ username, token: "wrongtoken" as AccessToken }, { - amount: userInfo.balance.amount - }) - ) - - }, - }, - test_deleteAccount: { - "balance-not-zero": async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - - await failOrThrow("balance-not-zero", () => - api.deleteAccount({ username, token: adminToken }) - ) - - }, - "not-found": async () => { - await failOrThrow("not-found", () => - api.deleteAccount({ username: "not-found", token: adminToken }) - ) - }, - "username-reserved": async () => { - await failOrThrow("username-reserved", () => - api.deleteAccount({ username: "admin", token: adminToken }) - ) - await failOrThrow("username-reserved", () => - api.deleteAccount({ username: "bank", token: adminToken }) - ) - }, - success: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - - const adminInfo = await succeedOrThrow(() => - api.getAccount({ username: "admin", token: adminToken }) - ) - - const adminAccount = parsePaytoUri(adminInfo.payto_uri)! - adminAccount.params["message"] = "all my money" - const withSubject = stringifyPaytoUri(adminAccount) - - await succeedOrThrow(() => - api.createTransaction({ username, token }, { - payto_uri: withSubject, - amount: userInfo.balance.amount - }) - ) - - }, - unauthorized: async () => { - const username = "harness-" + encodeCrock(getRandomBytes(10)).toLowerCase(); - - await succeedOrThrow(() => - api.createAccount(adminToken, { - name: username, - username, password: "123" - }) - ) - - const { token } = await createRandomTestUser(api, adminToken) - await failOrThrow("unauthorized", () => - api.deleteAccount({ username: username, token }) - ) - - }, - }, - test_getAccount: { - "not-found": async () => { - await failOrThrow("not-found", () => - api.getAccount({ username: "not-found", token: adminToken }) - ) - - }, - success: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - }, - unauthorized: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - await failOrThrow("unauthorized", () => - api.getAccount({ username, token: "wrongtoken" as AccessToken }) - ) - }, - }, - test_getAccounts: { - success: async () => { - await succeedOrThrow(() => - api.getAccounts(adminToken) - ) - await succeedOrThrow(() => - api.getAccounts(adminToken, { - account: "admin" - }) - ) - await succeedOrThrow(() => - api.getAccounts(adminToken, undefined, { - order: "dec", - limit: 10, - offset: "1" - }) - ) - }, - unauthorized: async () => { - await failOrThrow("unauthorized", () => - api.getAccounts("ASDASD" as AccessToken) - ) - }, - }, - test_getConfig: { - success: async () => { - const config = await succeedOrThrow(() => api.getConfig()) - - if (!api.isCompatible(config.version)) { - throw Error(`not compatible with server ${config.version}`) - } - - }, - }, - test_getMonitor: { - "unauthorized": async () => { - await failOrThrow("unauthorized", () => ( - api.getMonitor("wrongtoken" as AccessToken) - )) - - }, - "invalid-input": async () => { - - await failOrThrow("invalid-input", () => ( - api.getMonitor(adminToken, { - timeframe: TalerCorebankApi.MonitorTimeframeParam.day, - which: 100 - }) - )) - - }, - "monitor-not-supported": undefined, - success: async () => { - - await succeedOrThrow(() => ( - api.getMonitor(adminToken) - )) - - await succeedOrThrow(() => ( - api.getMonitor(adminToken, { - timeframe: TalerCorebankApi.MonitorTimeframeParam.day, - which: (new Date()).getDate() - 1 - }) - )) - - }, - }, - test_getPublicAccounts: { - success: async () => { - await succeedOrThrow(() => ( - api.getPublicAccounts() - )) - - await succeedOrThrow(() => ( - api.getPublicAccounts({ - order: "asc" - }) - )) - await succeedOrThrow(() => ( - api.getPublicAccounts({ - order: "dec" - }) - )) - await succeedOrThrow(() => ( - api.getPublicAccounts({ - order: "dec", limit: 10, offset: String(1) - }) - )) - }, - }, - test_getTransactionById: { - "not-found": async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - await failOrThrow("not-found", () => - api.getTransactionById({ username, token }, 123123123) - ) - }, - success: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - const { username: otherUser, token: otherToken } = await createRandomTestUser(api, adminToken) - - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - const otherInfo = await succeedOrThrow(() => - api.getAccount({ username: otherUser, token: otherToken }) - ) - const otherAccount = parsePaytoUri(otherInfo.payto_uri)! - otherAccount.params["message"] = "all" - - await succeedOrThrow(() => - api.createTransaction({ username, token }, { - payto_uri: stringifyPaytoUri(otherAccount), - amount: userInfo.balance.amount - }) - ) - - const txs = await succeedOrThrow(() => api.getTransactions({ username, token }, { - limit: 5, - order: "asc" - })) - const rowId = txs.transactions[0].row_id - - await succeedOrThrow(() => - api.getTransactionById({ username, token }, rowId) - ) - - }, - unauthorized: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - await failOrThrow("unauthorized", () => - api.getTransactionById({ username, token: "wrongtoken" as AccessToken }, 123123123) - ) - }, - }, - test_getTransactions: { - "not-found": async () => { - await failOrThrow("not-found", () => api.getTransactions({ - username: "not-found", - token: adminToken, - })) - }, - success: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - // await succeedOrThrow(() => api.getTransactions(creds)) - const txs = await succeedOrThrow(() => api.getTransactions({ username, token }, { - limit: 5, - order: "asc" - })) - }, - unauthorized: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - - await failOrThrow("unauthorized", () => api.getTransactions({ - username: username, - token: "wrongtoken" as AccessToken, - })) - - }, - }, - test_getWithdrawalById: { - "invalid-id": async () => { - - await failOrThrow("invalid-id", () => - api.getWithdrawalById("invalid") - ) - - }, - "not-found": async () => { - await failOrThrow("not-found", () => - api.getWithdrawalById("11111111-1111-1111-1111-111111111111") - ) - - }, - success: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - const userInfo = await succeedOrThrow(() => - api.getAccount({ username, token }) - ) - const { withdrawal_id } = await succeedOrThrow(() => - api.createWithdrawal({ username, token }, { - amount: userInfo.balance.amount - }) - ) - await succeedOrThrow(() => - api.getWithdrawalById(withdrawal_id) - ) - }, - }, - test_updateAccount: { - "cant-change-legal-name-or-admin": async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - - await failOrThrow("cant-change-legal-name-or-admin", () => - api.updateAccount({ username, token }, { - name: "something else", - }) - ) - - }, - "not-found": async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - await failOrThrow("not-found", () => - api.updateAccount({ username: "notfound", token }, { - challenge_contact_data: { - email: "asd@Aasd.com" - } - }) - ) - }, - success: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - - await succeedOrThrow(() => - api.updateAccount({ username, token }, { - challenge_contact_data: { - email: "asd@Aasd.com" - } - }) - ) - - }, - unauthorized: async () => { - - await failOrThrow("unauthorized", () => - api.updateAccount({ username: "notfound", token: "wrongtoken" as AccessToken }, { - challenge_contact_data: { - email: "asd@Aasd.com" - } - }) - ) - }, - }, - test_updatePassword: { - "not-found": async () => { - - await failOrThrow("not-found", () => - api.updatePassword({ username: "notfound", token: adminToken }, { - old_password: "123", - new_password: "234" - }) - ) - - - }, - "old-password-invalid-or-not-allowed": async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - - await failOrThrow("old-password-invalid-or-not-allowed", () => - api.updatePassword({ username, token }, { - old_password: "1233", - new_password: "234" - }) - ) - - }, - success: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - - await succeedOrThrow(() => - api.updatePassword({ username, token }, { - old_password: "123", - new_password: "234" - }) - ) - - - }, - unauthorized: async () => { - const { username, token } = await createRandomTestUser(api, adminToken) - await failOrThrow("unauthorized", () => - api.updatePassword({ username: "admin", token }, { - old_password: "123", - new_password: "234" - }) - ) - - - }, - }, - } -} - -export function createTestForBankRevenue(bank: TalerCoreBankHttpClient, adminToken: AccessToken): TestForApi<TalerRevenueHttpClient> { - - return { - test_getHistory: { - "endpoint-wrong-or-username-wrong": async () => { - const history = await failOrThrow("endpoint-wrong-or-username-wrong", () => - bank.getRevenueAPI("notfound").getHistory("wrongtoken" as AccessToken) - ) - }, - "invalid-input": undefined, - success: async () => { - const { token: exchangeToken, username: exchangeUsername } = await createRandomTestUser(bank, adminToken, { - is_taler_exchange: true - }) - const { token: merchantToken, username: merchantUsername } = await createRandomTestUser(bank, adminToken) - const config = await succeedOrThrow(() => bank.getConfig()) - - const merchantinfo = await succeedOrThrow(() => - bank.getAccount({ username: merchantUsername, token: merchantToken }) - ) - const account = parsePaytoUri(merchantinfo.payto_uri)! - account.params["message"] = "all" - - const amount = Amounts.stringify({ - currency: config.currency, - fraction: 0, - value: 1 - }) - - await succeedOrThrow(() => - bank.createTransaction({ username: exchangeUsername, token: exchangeToken }, { - payto_uri: stringifyPaytoUri(account), - amount - }) - ) - const history = await succeedOrThrow(() => - bank.getRevenueAPI(merchantUsername).getHistory(merchantToken) - ) - }, - unauthorized: async () => { - const { token: merchantToken, username: merchantUsername } = await createRandomTestUser(bank, adminToken) - const history = await failOrThrow("unauthorized", () => - bank.getRevenueAPI(merchantUsername).getHistory("wrongtoken" as AccessToken) - ) - }, - } - } -} - -export function createTestForBankWireGateway(bank: TalerCoreBankHttpClient, adminToken: AccessToken): TestForApi<TalerWireGatewayHttpClient> { - return { - //not used in production - test_addIncoming: { - "invalid-input": undefined, - "not-found": undefined, - "reserve-id-already-used": undefined, - success: undefined, - unauthorized: undefined, - }, - test_getHistoryIncoming: { - "invalid-input": async () => { - }, - "not-found": async () => { - }, - success: async () => { - }, - unauthorized: async () => { - }, - }, - test_getHistoryOutgoing: { - "invalid-input": async () => { - }, - "not-found": async () => { - }, - success: async () => { - }, - unauthorized: async () => { - }, - }, - test_transfer: { - "invalid-input": async () => { - }, - "not-found": async () => { - }, - "request-uid-already-used": async () => { - }, - success: async () => { - const { token: exchangeToken, username: exchangeUsername } = await createRandomTestUser(bank, adminToken, { - is_taler_exchange: true - }) - const { token: merchantToken, username: merchantUsername } = await createRandomTestUser(bank, adminToken) - const config = await succeedOrThrow(() => bank.getConfig()) - - const merchantInfo = await succeedOrThrow(() => - bank.getAccount({ username: merchantUsername, token: merchantToken }) - ) - const account = parsePaytoUri(merchantInfo.payto_uri)! - account.params["message"] = "all" - - const amount = Amounts.stringify({ - currency: config.currency, - fraction: 0, - value: 1 - }) - const resp = await succeedOrThrow(() => - bank.getWireGatewayAPI(merchantUsername).transfer(exchangeToken, { - amount, - credit_account: merchantInfo.payto_uri, - exchange_base_url: "", - request_uid: "", - wtid: "" - }) - ) - - }, - unauthorized: async () => { - }, - } - } -} - - -export async function createRandomTestUser(api: TalerCoreBankHttpClient, adminToken: AccessToken, options: Partial<TalerCorebankApi.RegisterAccountRequest> = {}) { - const username = "harness-" + encodeCrock(getRandomBytes(10)).toLowerCase(); - await succeedOrThrow(() => - api.createAccount(adminToken, { - name: username, - username, password: "123", - ...options - }) - ) - const { access_token } = await succeedOrThrow(() => - api.getAuthenticationAPI(username).createAccessToken("123", { - scope: "readwrite" - }) - ) - return { username, token: access_token } -} diff --git a/packages/taler-harness/src/index.ts b/packages/taler-harness/src/index.ts @@ -52,7 +52,6 @@ import { } from "@gnu-taler/taler-wallet-core"; import { deepStrictEqual } from "assert"; import fs from "fs"; -import { createRandomTestUser, createTestForBankCore } from "http-client/bank-core.js"; import os from "os"; import path from "path"; import { runBench1 } from "./bench1.js"; @@ -77,8 +76,9 @@ process.on("unhandledRejection", (error: any) => { }); declare const __VERSION__: string; +declare const __GIT_HASH__: string; function printVersion(): void { - console.log(__VERSION__); + console.log(`${__VERSION__} ${__GIT_HASH__}`); process.exit(0); } @@ -657,95 +657,12 @@ deploymentCli process.exit(2); }); - -type TestResult = { testName: string, caseName: string, result: "skiped" | "ok" | "fail", error?: any } - -async function getTestSummary<T extends object>(filter: string | undefined, ...apis: Array<TestForApi<T>>) { - const regex = !filter ? undefined : new RegExp(filter) - const apiState = await Promise.all(apis.flatMap(api => Object.entries(api).flatMap(([testName, casesMap]) => { - return Object.entries(casesMap).map(async ([caseName, caseFunc]): Promise<TestResult> => { - if (!caseFunc) { - return { testName, caseName, result: "skiped" as const } - } - if (regex && !regex.test(`${testName}:${caseName}`)) { - return { testName, caseName, result: "skiped" as const } - } - return caseFunc() - .then(r => ({ testName, caseName, result: "ok" as const })) - .catch(error => ({ testName, caseName, result: "fail" as const, error })) - }) - }))) - - return apiState.reduce((prev, testResult) => { - if (testResult.result === "ok") { - prev.ok.push(testResult) - } - if (testResult.result === "skiped") { - prev.skiped.push(testResult) - } - if (testResult.result === "fail") { - prev.fail.push(testResult) - } - return prev - }, { "ok": [] as TestResult[], "skiped": [] as TestResult[], "fail": [] as TestResult[] }) -} - -deploymentCli - .subcommand("testBankAPI", "test-bank-api", { - help: "test api compatibility.", - }) - .requiredArgument("corebankApiBaseUrl", clk.STRING) - .maybeOption("adminPwd", ["--admin-password"], clk.STRING) - .maybeOption("filter", ["--filter"], clk.STRING) - .flag("showCurl", ["--show-curl"]) - .action(async (args) => { - const httpLib = createPlatformHttpLib(); - const api = new TalerCoreBankHttpClient(args.testBankAPI.corebankApiBaseUrl, httpLib); - - process.stdout.write("config: "); - const config = await api.getConfig() - if (!api.isCompatible(config.body.version)) { - console.log("fail") - return; - } else { - console.log("ok") - } - - if (!args.testBankAPI.adminPwd) { - console.log("no admin password, exit") - return; - } - - const resp = await api.getAuthenticationAPI("admin").createAccessToken(args.testBankAPI.adminPwd, { - scope: "readwrite" - }) - - if (args.testBankAPI.showCurl) { - setPrintHttpRequestAsCurl(true) - } - - if (resp.type === "fail") { - console.log("wrong admin password") - return; - } - - const bankCore = createTestForBankCore(api, resp.body.access_token) - - const summary = await getTestSummary(args.testBankAPI.filter, bankCore) - - console.log("successful tests:", summary.ok.length) - console.log("uncompleted tests:", summary.skiped.length) - summary.skiped.forEach((testResult) => { - if (testResult.result === "skiped") { - console.log(" ", testResult.testName, testResult.caseName) - } - }) - console.log("failed tests:", summary.fail.length) - summary.fail.forEach((testResult, i) => { - console.log(i, ")", testResult) - }) - }); - +type TestResult = { + testName: string; + caseName: string; + result: "skiped" | "ok" | "fail"; + error?: any; +}; deploymentCli .subcommand("coincfg", "gen-coin-config", { diff --git a/packages/taler-harness/src/integrationtests/test-denom-unoffered.ts b/packages/taler-harness/src/integrationtests/test-denom-unoffered.ts @@ -127,9 +127,9 @@ export async function runDenomUnofferedTest(t: GlobalTestState) { // TalerErrorCode.MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_KEY_NOT_FOUND, // ); - await walletClient.call(WalletApiOperation.AddExchange, { + // Force updating the exchange entry so that the wallet knows about the new denominations. + await walletClient.call(WalletApiOperation.UpdateExchangeEntry, { exchangeBaseUrl: exchange.baseUrl, - forceUpdate: true, }); await walletClient.call(WalletApiOperation.DeleteTransaction, { diff --git a/packages/taler-harness/src/integrationtests/test-peer-to-peer-push.ts b/packages/taler-harness/src/integrationtests/test-peer-to-peer-push.ts @@ -22,17 +22,16 @@ import { AmountString, Duration, NotificationType, - TalerUriAction, TransactionMajorState, TransactionMinorState, TransactionType, WalletNotification, j2s, - stringifyTalerUri, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { GlobalTestState } from "../harness/harness.js"; import { + applyTimeTravelV2, createSimpleTestkudosEnvironmentV2, createWalletDaemonWithClient, withdrawViaBankV2, @@ -139,7 +138,7 @@ export async function runPeerToPeerPushTest(t: GlobalTestState) { const acceptResp = await w2.walletClient.call( WalletApiOperation.ConfirmPeerPushCredit, { - peerPushCreditId: checkResp.peerPushCreditId, + transactionId: checkResp.transactionId, }, ); @@ -157,6 +156,7 @@ export async function runPeerToPeerPushTest(t: GlobalTestState) { console.log(`txn1: ${j2s(txn1)}`); console.log(`txn2: ${j2s(txn2)}`); + // We expect insufficient balance here! const ex1 = await t.assertThrowsTalerErrorAsync(async () => { await w1.walletClient.call(WalletApiOperation.InitiatePeerPushDebit, { partialContractTerms: { @@ -168,6 +168,54 @@ export async function runPeerToPeerPushTest(t: GlobalTestState) { }); console.log("got expected exception detail", j2s(ex1.errorDetail)); + + const initiateResp2 = await w1.walletClient.call( + WalletApiOperation.InitiatePeerPushDebit, + { + partialContractTerms: { + summary: "second tx, will expire", + amount: "TESTKUDOS:5" as AmountString, + purse_expiration, + }, + }, + ); + + const peerPushReadyCond2 = w1.walletClient.waitForNotificationCond( + (x) => + x.type === NotificationType.TransactionStateTransition && + x.newTxState.major === TransactionMajorState.Pending && + x.newTxState.minor === TransactionMinorState.Ready && + x.transactionId === initiateResp2.transactionId, + ); + + await peerPushReadyCond2; + + const timetravelOffsetMs = Duration.toMilliseconds( + Duration.fromSpec({ days: 5 }), + ); + + await exchange.stop(); + exchange.setTimetravel(timetravelOffsetMs); + await exchange.start(); + await exchange.pingUntilAvailable(); + + await w1.walletClient.call(WalletApiOperation.TestingSetTimetravel, { + offsetMs: timetravelOffsetMs, + }); + + await w1.walletClient.call( + WalletApiOperation.TestingWaitTransactionsFinal, + {}, + ); + + const txDetails2 = await w1.walletClient.call( + WalletApiOperation.GetTransactionById, + { + transactionId: initiateResp2.transactionId, + }, + ); + + console.log(`tx details 2: ${j2s(txDetails2)}`); } runPeerToPeerPushTest.suites = ["wallet"]; diff --git a/packages/taler-harness/src/integrationtests/test-refund.ts b/packages/taler-harness/src/integrationtests/test-refund.ts @@ -23,6 +23,7 @@ import { MerchantApiClient, NotificationType, TransactionMajorState, + TransactionType, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { GlobalTestState } from "../harness/harness.js"; @@ -58,7 +59,6 @@ export async function runRefundTest(t: GlobalTestState) { await withdrawalRes.withdrawalFinishedCond; // Set up order. - const orderResp = await merchantClient.createOrder({ order: { summary: "Buy me!", @@ -94,6 +94,15 @@ export async function runRefundTest(t: GlobalTestState) { t.assertTrue(orderStatus.order_status === "paid"); + + { + const tx = await wallet.client.call(WalletApiOperation.GetTransactionById, { + transactionId: r1.transactionId, + }); + + t.assertTrue(tx.type === TransactionType.Payment && tx.refundPending === undefined) + } + const ref = await merchantClient.giveRefund({ amount: "TESTKUDOS:5", instance: "default", @@ -113,7 +122,6 @@ export async function runRefundTest(t: GlobalTestState) { const r = await wallet.client.call(WalletApiOperation.StartRefundQuery, { transactionId: r1.transactionId, }); - console.log(r); await refundFinishedCond; } @@ -127,6 +135,14 @@ export async function runRefundTest(t: GlobalTestState) { console.log(JSON.stringify(r2, undefined, 2)); } + { + const tx = await wallet.client.call(WalletApiOperation.GetTransactionById, { + transactionId: r1.transactionId, + }); + + t.assertTrue(tx.type === TransactionType.Payment && tx.refundPending === undefined) + } + // FIXME: Test is incomplete without this! // { // const refundQueriedCond = wallet.waitForNotificationCond( diff --git a/packages/taler-harness/src/integrationtests/test-revocation.ts b/packages/taler-harness/src/integrationtests/test-revocation.ts @@ -180,9 +180,8 @@ export async function runRevocationTest(t: GlobalTestState) { // FIXME: this shouldn't be necessary once https://bugs.taler.net/n/6565 // is implemented. - await walletClient.call(WalletApiOperation.AddExchange, { + await walletClient.call(WalletApiOperation.UpdateExchangeEntry, { exchangeBaseUrl: exchange.baseUrl, - forceUpdate: true, }); await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); const bal = await walletClient.call(WalletApiOperation.GetBalances, {}); @@ -218,9 +217,8 @@ export async function runRevocationTest(t: GlobalTestState) { // FIXME: this shouldn't be necessary once https://bugs.taler.net/n/6565 // is implemented. - await walletClient.call(WalletApiOperation.AddExchange, { + await walletClient.call(WalletApiOperation.UpdateExchangeEntry, { exchangeBaseUrl: exchange.baseUrl, - forceUpdate: true, }); await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); { diff --git a/packages/taler-harness/src/integrationtests/test-wallet-balance.ts b/packages/taler-harness/src/integrationtests/test-wallet-balance.ts @@ -75,6 +75,8 @@ export async function runWalletBalanceTest(t: GlobalTestState) { fulfillment_url: "taler://fulfillment-success/thx", }; + console.log("creating order"); + const orderResp = await merchantClient.createOrder({ order, }); @@ -117,6 +119,8 @@ export async function runWalletBalanceTest(t: GlobalTestState) { Amounts.isZero(preparePayResult.balanceDetails.balanceMerchantDepositable), ); + console.log("waiting for transactions to finalize"); + await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); } diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-conversion.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-conversion.ts @@ -29,6 +29,8 @@ import { j2s, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import * as http from "node:http"; +import { defaultCoinConfig } from "../harness/denomStructures.js"; import { BankService, ExchangeService, @@ -38,8 +40,6 @@ import { setupDb, } from "../harness/harness.js"; import { createWalletDaemonWithClient } from "../harness/helpers.js"; -import { defaultCoinConfig } from "../harness/denomStructures.js"; -import * as http from "node:http"; const logger = new Logger("test-withdrawal-conversion.ts"); @@ -196,10 +196,9 @@ export async function runWithdrawalConversionTest(t: GlobalTestState) { console.log(`withdrawal details: ${j2s(infoRes)}`); - t.assertAmountEquals( - infoRes.withdrawalAccountList[0].transferAmount, - "FOO:123", - ); + const checkTransferAmount = infoRes.withdrawalAccountsList[0].transferAmount; + t.assertTrue(checkTransferAmount != null); + t.assertAmountEquals(checkTransferAmount, "FOO:123"); const tStart = AbsoluteTime.now(); @@ -217,10 +216,10 @@ export async function runWithdrawalConversionTest(t: GlobalTestState) { logger.info("AcceptManualWithdrawal finished"); logger.info(`result: ${j2s(wres)}`); - t.assertAmountEquals( - wres.withdrawalAccountsList[0].transferAmount, - "FOO:123", - ); + const acceptedTransferAmount = wres.withdrawalAccountsList[0].transferAmount; + t.assertTrue(acceptedTransferAmount != null); + + t.assertAmountEquals(acceptedTransferAmount, "FOO:123"); const txInfo = await walletClient.call( WalletApiOperation.GetTransactionById, @@ -234,9 +233,9 @@ export async function runWithdrawalConversionTest(t: GlobalTestState) { txInfo.withdrawalDetails.type, WithdrawalType.ManualTransfer, ); - t.assertTrue(!!txInfo.withdrawalDetails.exchangeCreditAccounts); + t.assertTrue(!!txInfo.withdrawalDetails.exchangeCreditAccountDetails); t.assertDeepEqual( - txInfo.withdrawalDetails.exchangeCreditAccounts[0].transferAmount, + txInfo.withdrawalDetails.exchangeCreditAccountDetails[0].transferAmount, "FOO:123", ); diff --git a/packages/taler-harness/tsconfig.json b/packages/taler-harness/tsconfig.json @@ -2,7 +2,7 @@ "compileOnSave": true, "compilerOptions": { "composite": true, - "target": "ES2018", + "target": "ES2020", "module": "Node16", "moduleResolution": "Node16", "sourceMap": true, diff --git a/packages/taler-util/package.json b/packages/taler-util/package.json @@ -65,17 +65,17 @@ }, "devDependencies": { "@types/node": "^18.11.17", - "ava": "^4.3.3", - "esbuild": "^0.17.7", - "prettier": "^2.8.8", - "typescript": "^5.2.2" + "ava": "^6.0.1", + "esbuild": "^0.19.9", + "prettier": "^3.1.1", + "typescript": "^5.3.3" }, "dependencies": { - "big-integer": "^1.6.51", - "fflate": "^0.7.4", - "hash-wasm": "^4.9.0", + "big-integer": "^1.6.52", + "fflate": "^0.8.1", + "hash-wasm": "^4.11.0", "jed": "^1.1.1", - "tslib": "^2.5.3" + "tslib": "^2.6.2" }, "ava": { "files": [ diff --git a/packages/taler-util/src/codec.ts b/packages/taler-util/src/codec.ts @@ -14,12 +14,17 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ +import { j2s } from "./helpers.js"; +import { Logger } from "./logging.js"; + /** * Type-safe codecs for converting from/to JSON. */ /* eslint-disable @typescript-eslint/ban-types */ +const logger = new Logger("codec.ts"); + /** * Error thrown when decoding fails. */ @@ -322,6 +327,40 @@ export function codecForString(): Codec<string> { } /** + * Return a codec for a value that must be a string. + */ +export function codecForStringURL(shouldEndWithSlash?: boolean): Codec<string> { + return { + decode(x: any, c?: Context): string { + if (typeof x !== "string") { + throw new DecodingError( + `expected string at ${renderContext(c)} but got ${typeof x}`, + ); + } + if (shouldEndWithSlash && !x.endsWith("/")) { + throw new DecodingError( + `expected URL string that ends with slash at ${renderContext( + c, + )} but got ${x}`, + ); + } + try { + const url = new URL(x); + return x; + } catch (e) { + if (e instanceof Error) { + throw new DecodingError(e.message); + } else { + throw new DecodingError( + `expected an URL string at ${renderContext(c)} but got "${x}"`, + ); + } + } + }, + }; +} + +/** * Codec that allows any value. */ export function codecForAny(): Codec<any> { @@ -432,6 +471,9 @@ export function codecForEither<T extends Array<Codec<unknown>>>( continue; } } + if (logger.shouldLogTrace()) { + logger.trace(`offending value: ${j2s(x)}`); + } throw new DecodingError( `No alternative matched at at ${renderContext(c)}`, ); diff --git a/packages/taler-util/src/errors.ts b/packages/taler-util/src/errors.ts @@ -103,6 +103,11 @@ export interface DetailsMap { requestMethod: string; httpStatusCode: number; validationError?: string; + /** + * Content type of the response, usually only specified if not the + * expected content type. + */ + contentType?: string; }; [TalerErrorCode.WALLET_EXCHANGE_COIN_SIGNATURE_INVALID]: empty; [TalerErrorCode.WALLET_WITHDRAWAL_GROUP_INCOMPLETE]: { @@ -197,17 +202,19 @@ export class TalerProtocolViolationError extends Error { } // compute a subset of TalerError, just for http request -type HttpErrors = TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT +type HttpErrors = + | TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT | TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED | TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE | TalerErrorCode.WALLET_NETWORK_ERROR | TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR; type TalerHttpErrorsDetails = { - [code in HttpErrors]: TalerError<DetailsMap[code]> -} + [code in HttpErrors]: TalerError<DetailsMap[code]>; +}; -export type TalerHttpError = TalerHttpErrorsDetails[keyof TalerHttpErrorsDetails] +export type TalerHttpError = + TalerHttpErrorsDetails[keyof TalerHttpErrorsDetails]; export class TalerError<T = any> extends Error { errorDetail: TalerErrorDetail & T; @@ -243,7 +250,6 @@ export class TalerError<T = any> extends Error { ): this is TalerError<DetailsMap[C]> { return this.errorDetail.code === code; } - } /** diff --git a/packages/taler-util/src/http-client/bank-conversion.ts b/packages/taler-util/src/http-client/bank-conversion.ts @@ -2,14 +2,18 @@ import { AmountJson, Amounts } from "../amounts.js"; import { HttpRequestLibrary } from "../http-common.js"; import { HttpStatusCode } from "../http-status-codes.js"; import { createPlatformHttpLib } from "../http.js"; -import { FailCasesByMethod, ResultByMethod, opKnownFailure, opSuccess, opUnknownFailure } from "../operation.js"; +import { FailCasesByMethod, ResultByMethod, opEmptySuccess, opKnownFailure, opSuccess, opUnknownFailure } from "../operation.js"; import { TalerErrorCode } from "../taler-error-codes.js"; import { codecForTalerErrorDetail } from "../wallet-types.js"; import { + AccessToken, + TalerBankConversionApi, + UserAndToken, codecForCashinConversionResponse, codecForCashoutConversionResponse, codecForConversionBankConfig } from "./types.js"; +import { makeBearerTokenAuthHeader } from "./utils.js"; export type TalerBankConversionResultByMethod<prop extends keyof TalerBankConversionHttpClient> = ResultByMethod<TalerBankConversionHttpClient, prop> export type TalerBankConversionErrorsByMethod<prop extends keyof TalerBankConversionHttpClient> = FailCasesByMethod<TalerBankConversionHttpClient, prop> @@ -70,7 +74,7 @@ export class TalerBankConversionHttpClient { } } case HttpStatusCode.Conflict: return opKnownFailure("amount-too-small", resp); - case HttpStatusCode.NotImplemented: return opKnownFailure("cashout-not-supported", resp); + case HttpStatusCode.NotImplemented: return opKnownFailure("conversion-not-supported", resp); default: return opUnknownFailure(resp, await resp.text()) } } @@ -103,11 +107,31 @@ export class TalerBankConversionHttpClient { } } case HttpStatusCode.Conflict: return opKnownFailure("amount-too-small", resp); - case HttpStatusCode.NotImplemented: return opKnownFailure("cashout-not-supported", resp); + case HttpStatusCode.NotImplemented: return opKnownFailure("conversion-not-supported", resp); default: return opUnknownFailure(resp, await resp.text()) } } + /** + * https://docs.taler.net/core/api-bank-conversion-info.html#post--conversion-rate + * + */ + async updateConversionRate(auth: AccessToken, body: TalerBankConversionApi.ConversionRate) { + const url = new URL(`conversion-rate`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + headers: { + Authorization: makeBearerTokenAuthHeader(auth) + }, + body + }); + switch (resp.status) { + case HttpStatusCode.NoContent: return opEmptySuccess() + case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); + case HttpStatusCode.NotImplemented: return opKnownFailure("conversion-not-supported", resp); + default: return opUnknownFailure(resp, await resp.text()) + } + } } diff --git a/packages/taler-util/src/http-client/bank-core.ts b/packages/taler-util/src/http-client/bank-core.ts @@ -15,8 +15,6 @@ */ import { - AmountJson, - Amounts, HttpStatusCode, LibtoolVersion, TalerErrorCode, @@ -28,12 +26,12 @@ import { } from "@gnu-taler/taler-util/http"; import { FailCasesByMethod, ResultByMethod, opEmptySuccess, opFixedSuccess, opKnownFailure, opSuccess, opUnknownFailure } from "../operation.js"; import { TalerAuthenticationHttpClient } from "./authentication.js"; +import { TalerBankConversionHttpClient } from "./bank-conversion.js"; import { TalerBankIntegrationHttpClient } from "./bank-integration.js"; import { TalerRevenueHttpClient } from "./bank-revenue.js"; import { TalerWireGatewayHttpClient } from "./bank-wire.js"; -import { AccessToken, PaginationParams, TalerCorebankApi, UserAndToken, codecForAccountData, codecForBankAccountCreateWithdrawalResponse, codecForBankAccountGetWithdrawalResponse, codecForBankAccountTransactionInfo, codecForBankAccountTransactionsResponse, codecForCashinConversionResponse, codecForCashoutConversionResponse, codecForCashoutPending, codecForCashoutStatusResponse, codecForCashouts, codecForCoreBankConfig, codecForGlobalCashouts, codecForListBankAccountsResponse, codecForMonitorResponse, codecForPublicAccountsResponse } from "./types.js"; +import { AccessToken, PaginationParams, TalerCorebankApi, UserAndToken, WithdrawalOperationStatus, codecForAccountData, codecForBankAccountCreateWithdrawalResponse, codecForBankAccountTransactionInfo, codecForBankAccountTransactionsResponse, codecForCashoutPending, codecForCashoutStatusResponse, codecForCashouts, codecForCoreBankConfig, codecForCreateTransactionResponse, codecForGlobalCashouts, codecForListBankAccountsResponse, codecForMonitorResponse, codecForPublicAccountsResponse, codecForRegisterAccountResponse, codecForWithdrawalPublicInfo } from "./types.js"; import { addPaginationParams, makeBearerTokenAuthHeader } from "./utils.js"; -import { TalerBankConversionHttpClient } from "./bank-conversion.js"; export type TalerCoreBankResultByMethod<prop extends keyof TalerCoreBankHttpClient> = ResultByMethod<TalerCoreBankHttpClient, prop> @@ -62,7 +60,7 @@ export class TalerCoreBankHttpClient { } /** - * https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME + * https://docs.taler.net/core/api-corebank.html#config * */ async getConfig() { @@ -94,7 +92,7 @@ export class TalerCoreBankHttpClient { }, }); switch (resp.status) { - case HttpStatusCode.Created: return opEmptySuccess() + case HttpStatusCode.Ok: return opSuccess(resp, codecForRegisterAccountResponse()) case HttpStatusCode.BadRequest: return opKnownFailure("invalid-phone-or-email", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); case HttpStatusCode.Conflict: { @@ -105,6 +103,7 @@ export class TalerCoreBankHttpClient { case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE: return opKnownFailure("payto-already-exists", resp); case TalerErrorCode.BANK_UNALLOWED_DEBIT: return opKnownFailure("insufficient-funds", resp); case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT: return opKnownFailure("username-reserved", resp); + case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: return opKnownFailure("user-cant-set-debt", resp); default: return opUnknownFailure(resp, body) } } @@ -157,10 +156,17 @@ export class TalerCoreBankHttpClient { case HttpStatusCode.NoContent: return opEmptySuccess() case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); - //FIXME: missing error code for cases: - // * change legal name - // * admin tries to change its own account - case HttpStatusCode.Forbidden: return opKnownFailure("cant-change-legal-name-or-admin", resp); + case HttpStatusCode.Conflict: { + const body = await resp.json() + const details = codecForTalerErrorDetail().decode(body) + switch (details.code) { + case TalerErrorCode.BANK_NON_ADMIN_PATCH_LEGAL_NAME: return opKnownFailure("user-cant-change-name", resp); + case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: return opKnownFailure("user-cant-change-debt", resp); + case TalerErrorCode.BANK_NON_ADMIN_PATCH_CASHOUT: return opKnownFailure("user-cant-change-cashout", resp); + case TalerErrorCode.BANK_NON_ADMIN_PATCH_CONTACT: return opKnownFailure("user-cant-change-contact", resp); + default: return opUnknownFailure(resp, body) + } + } default: return opUnknownFailure(resp, await resp.text()) } } @@ -182,25 +188,31 @@ export class TalerCoreBankHttpClient { case HttpStatusCode.NoContent: return opEmptySuccess() case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); - //FIXME: add code to split cases - // * An admin account tried to make its account an exchange - // * A non-admin user tried to change properties reserved for the admin - case HttpStatusCode.Forbidden: return opKnownFailure("old-password-invalid-or-not-allowed", resp); + case HttpStatusCode.Conflict: { + const body = await resp.json() + const details = codecForTalerErrorDetail().decode(body) + switch (details.code) { + case TalerErrorCode.BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD: return opKnownFailure("user-require-old-password", resp); + case TalerErrorCode.BANK_PATCH_BAD_OLD_PASSWORD: return opKnownFailure("wrong-old-password", resp); + default: return opUnknownFailure(resp, body) + } + } default: return opUnknownFailure(resp, await resp.text()) } } /** - * https://docs.taler.net/core/get-$BANK_API_BASE_URL-public-accounts + * https://docs.taler.net/core/api-corebank.html#get--public-accounts * */ - async getPublicAccounts(pagination?: PaginationParams) { + async getPublicAccounts(filter: { account?: string } = {}, pagination?: PaginationParams) { const url = new URL(`public-accounts`, this.baseUrl); addPaginationParams(url, pagination) + if (filter.account !== undefined) { + url.searchParams.set("filter_name", filter.account) + } const resp = await this.httpLib.fetch(url.href, { method: "GET", - headers: { - }, }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccess(resp, codecForPublicAccountsResponse()) @@ -217,7 +229,7 @@ export class TalerCoreBankHttpClient { async getAccounts(auth: AccessToken, filter: { account?: string } = {}, pagination?: PaginationParams) { const url = new URL(`accounts`, this.baseUrl); addPaginationParams(url, pagination) - if (filter.account) { + if (filter.account !== undefined) { url.searchParams.set("filter_name", filter.account) } const resp = await this.httpLib.fetch(url.href, { @@ -259,7 +271,7 @@ export class TalerCoreBankHttpClient { // /** - * https://docs.taler.net/core/api-corebank.html#get-$BANK_API_BASE_URL-accounts-$account_name-transactions + * https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-transactions * */ async getTransactions(auth: UserAndToken, pagination?: PaginationParams) { @@ -274,14 +286,14 @@ export class TalerCoreBankHttpClient { switch (resp.status) { case HttpStatusCode.Ok: return opSuccess(resp, codecForBankAccountTransactionsResponse()) case HttpStatusCode.NoContent: return opFixedSuccess({ transactions: [] }) - case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); + case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); default: return opUnknownFailure(resp, await resp.text()) } } /** - * https://docs.taler.net/core/api-corebank.html#get-$BANK_API_BASE_URL-accounts-$account_name-transactions-$transaction_id + * https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-transactions-$TRANSACTION_ID * */ async getTransactionById(auth: UserAndToken, txid: number) { @@ -301,10 +313,10 @@ export class TalerCoreBankHttpClient { } /** - * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-accounts-$account_name-transactions + * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-transactions * */ - async createTransaction(auth: UserAndToken, body: TalerCorebankApi.CreateBankAccountTransactionCreate) { + async createTransaction(auth: UserAndToken, body: TalerCorebankApi.CreateTransactionRequest) { const url = new URL(`accounts/${auth.username}/transactions`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "POST", @@ -314,8 +326,7 @@ export class TalerCoreBankHttpClient { body, }); switch (resp.status) { - //FIXME: expect txid as response - case HttpStatusCode.NoContent: return opEmptySuccess() + case HttpStatusCode.Ok: return opSuccess(resp, codecForCreateTransactionResponse()) case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); @@ -338,7 +349,7 @@ export class TalerCoreBankHttpClient { // /** - * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-accounts-$account_name-withdrawals + * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals * */ async createWithdrawal(auth: UserAndToken, body: TalerCorebankApi.BankAccountCreateWithdrawalRequest) { @@ -360,13 +371,16 @@ export class TalerCoreBankHttpClient { } /** - * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-withdrawals-$withdrawal_id-abort + * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-abort * */ - async abortWithdrawalById(wid: string) { - const url = new URL(`withdrawals/${wid}/abort`, this.baseUrl); + async abortWithdrawalById(auth: UserAndToken, wid: string) { + const url = new URL(`accounts/${auth.username}/withdrawals/${wid}/abort`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "POST", + headers: { + Authorization: makeBearerTokenAuthHeader(auth.token) + }, }); switch (resp.status) { case HttpStatusCode.NoContent: return opEmptySuccess() @@ -379,13 +393,16 @@ export class TalerCoreBankHttpClient { } /** - * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-withdrawals-$withdrawal_id-confirm + * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-confirm * */ - async confirmWithdrawalById(wid: string) { - const url = new URL(`withdrawals/${wid}/confirm`, this.baseUrl); + async confirmWithdrawalById(auth: UserAndToken, wid: string) { + const url = new URL(`accounts/${auth.username}/withdrawals/${wid}/confirm`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "POST", + headers: { + Authorization: makeBearerTokenAuthHeader(auth.token) + }, }); switch (resp.status) { case HttpStatusCode.NoContent: return opEmptySuccess() @@ -396,9 +413,9 @@ export class TalerCoreBankHttpClient { const body = await resp.json() const details = codecForTalerErrorDetail().decode(body) switch (details.code) { - case TalerErrorCode.BANK_UNALLOWED_DEBIT: return opKnownFailure("insufficient-funds", resp); - case TalerErrorCode.BANK_CONFIRM_INCOMPLETE: return opKnownFailure("no-exchange-or-reserve-selected", resp); case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT: return opKnownFailure("previously-aborted", resp); + case TalerErrorCode.BANK_CONFIRM_INCOMPLETE: return opKnownFailure("no-exchange-or-reserve-selected", resp); + case TalerErrorCode.BANK_UNALLOWED_DEBIT: return opKnownFailure("insufficient-funds", resp); default: return opUnknownFailure(resp, body) } } @@ -407,16 +424,23 @@ export class TalerCoreBankHttpClient { } /** - * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-accounts-$account_name-withdrawals + * https://docs.taler.net/core/api-corebank.html#get--withdrawals-$WITHDRAWAL_ID * */ - async getWithdrawalById(wid: string) { + async getWithdrawalById(wid: string, wait?: { + old_state?: WithdrawalOperationStatus, + timeoutMs: number + }) { const url = new URL(`withdrawals/${wid}`, this.baseUrl); + if (wait) { + url.searchParams.set("long_poll_ms", String(wait.timeoutMs)) + url.searchParams.set("old_state", !wait.old_state ? "pending" : wait.old_state) + } const resp = await this.httpLib.fetch(url.href, { method: "GET", }); switch (resp.status) { - case HttpStatusCode.Ok: return opSuccess(resp, codecForBankAccountGetWithdrawalResponse()) + case HttpStatusCode.Ok: return opSuccess(resp, codecForWithdrawalPublicInfo()) //FIXME: missing in docs case HttpStatusCode.BadRequest: return opKnownFailure("invalid-id", resp) case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp) @@ -477,7 +501,6 @@ export class TalerCoreBankHttpClient { case HttpStatusCode.NoContent: return opEmptySuccess() case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); case HttpStatusCode.Conflict: return opKnownFailure("already-confirmed", resp); - //FIXME: should be 404 ? case HttpStatusCode.NotImplemented: return opKnownFailure("cashout-not-supported", resp); default: return opUnknownFailure(resp, await resp.text()) } diff --git a/packages/taler-util/src/http-client/bank-integration.ts b/packages/taler-util/src/http-client/bank-integration.ts @@ -6,6 +6,7 @@ import { TalerErrorCode } from "../taler-error-codes.js"; import { codecForTalerErrorDetail } from "../wallet-types.js"; import { TalerBankIntegrationApi, + WithdrawalOperationStatus, codecForBankWithdrawalOperationPostResponse, codecForBankWithdrawalOperationStatus, codecForIntegrationBankConfig @@ -43,13 +44,17 @@ export class TalerBankIntegrationHttpClient { } /** - * https://docs.taler.net/core/api-bank-integration.html#get-$BANK_API_BASE_URL-withdrawal-operation-$wopid + * https://docs.taler.net/core/api-bank-integration.html#get--withdrawal-operation-$WITHDRAWAL_ID * */ - async getWithdrawalOperationById(woid: string, timeoutMs?: number) { + async getWithdrawalOperationById(woid: string, wait?: { + old_state?: WithdrawalOperationStatus, + timeoutMs: number + }) { const url = new URL(`withdrawal-operation/${woid}`, this.baseUrl); - if (timeoutMs) { - url.searchParams.set("long_poll_ms", String(timeoutMs)) + if (wait) { + url.searchParams.set("long_poll_ms", String(wait.timeoutMs)) + url.searchParams.set("old_state", !wait.old_state ? "pending" : wait.old_state) } const resp = await this.httpLib.fetch(url.href, { method: "GET" @@ -80,7 +85,7 @@ export class TalerBankIntegrationHttpClient { switch (details.code) { case TalerErrorCode.BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT: return opKnownFailure("already-selected", resp); case TalerErrorCode.BANK_DUPLICATE_RESERVE_PUB_SUBJECT: return opKnownFailure("duplicated-reserve-id", resp); - // case TalerErrorCode.BANK_ACCOUNT_NOT_FOUND: return opKnownFailure("account-not-found", resp); + case TalerErrorCode.BANK_UNKNOWN_ACCOUNT: return opKnownFailure("account-not-found", resp); case TalerErrorCode.BANK_ACCOUNT_IS_NOT_EXCHANGE: return opKnownFailure("account-not-exchange", resp); default: return opUnknownFailure(resp, body) } diff --git a/packages/taler-util/src/http-client/bank-revenue.ts b/packages/taler-util/src/http-client/bank-revenue.ts @@ -24,7 +24,7 @@ export class TalerRevenueHttpClient { } /** - * https://docs.taler.net/core/api-bank-revenue.html#get-$BASE_URL-history + * https://docs.taler.net/core/api-bank-revenue.html#get--history * * @returns */ diff --git a/packages/taler-util/src/http-client/bank-wire.ts b/packages/taler-util/src/http-client/bank-wire.ts @@ -27,12 +27,10 @@ export class TalerWireGatewayHttpClient { } /** - * https://docs.taler.net/core/api-bank-wire.html#post-$BASE_URL-transfer + * https://docs.taler.net/core/api-bank-wire.html#post--transfer * */ - async transfer( - auth: string, - body: TalerWireGatewayApi.TransferRequest, + async transfer(auth: string, body: TalerWireGatewayApi.TransferRequest, ) { const url = new URL(`transfer`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { @@ -53,7 +51,7 @@ export class TalerWireGatewayHttpClient { } /** - * https://docs.taler.net/core/api-bank-wire.html#get-$BASE_URL-history-incoming + * https://docs.taler.net/core/api-bank-wire.html#get--history-incoming * */ async getHistoryIncoming(auth: string, pagination?: PaginationParams) { @@ -67,7 +65,7 @@ export class TalerWireGatewayHttpClient { }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccess(resp, codecForIncomingHistory()) - case HttpStatusCode.NoContent: return opFixedSuccess({ incoming_transactions: [], credit_account: "" }) + case HttpStatusCode.NoContent: return opFixedSuccess({ incoming_transactions: [] }) case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); @@ -75,8 +73,9 @@ export class TalerWireGatewayHttpClient { } // return readSuccessResponseJsonOrThrow(resp, codecForIncomingHistory()); } + /** - * https://docs.taler.net/core/api-bank-wire.html#get-$BASE_URL-history-outgoing + * https://docs.taler.net/core/api-bank-wire.html#get--history-outgoing * */ async getHistoryOutgoing(auth: string, pagination?: PaginationParams) { @@ -90,15 +89,16 @@ export class TalerWireGatewayHttpClient { }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccess(resp, codecForOutgoingHistory()) - case HttpStatusCode.NoContent: return opFixedSuccess({ outgoing_transactions: [], debit_account: "" }) + case HttpStatusCode.NoContent: return opFixedSuccess({ outgoing_transactions: [] }) case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); default: return opUnknownFailure(resp, await resp.text()) } } + /** - * https://docs.taler.net/core/api-bank-wire.html#post-$BASE_URL-admin-add-incoming + * https://docs.taler.net/core/api-bank-wire.html#post--admin-add-incoming * */ async addIncoming(auth: string, body: TalerWireGatewayApi.AddIncomingRequest,) { @@ -112,7 +112,6 @@ export class TalerWireGatewayHttpClient { }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccess(resp, codecForAddIncomingResponse()) - case HttpStatusCode.NoContent: return opFixedSuccess({ outgoing_transactions: [], debit_account: "" }) case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp); diff --git a/packages/taler-util/src/http-client/types.ts b/packages/taler-util/src/http-client/types.ts @@ -264,6 +264,7 @@ export const codecForIntegrationBankConfig = .property("name", codecForConstString("taler-bank-integration")) .property("version", codecForString()) .property("currency", codecForString()) + .property("currency_specification", codecForCurrencySpecificiation()) .build("TalerCorebankApi.IntegrationConfig"); export const codecForCoreBankConfig = (): Codec<TalerCorebankApi.Config> => @@ -273,8 +274,15 @@ export const codecForCoreBankConfig = (): Codec<TalerCorebankApi.Config> => .property("allow_conversion", codecForBoolean()) .property("allow_deletions", codecForBoolean()) .property("allow_registrations", codecForBoolean()) + .property("allow_edit_cashout_payto_uri", codecForBoolean()) + .property("allow_edit_name", codecForBoolean()) + .property("default_debit_threshold", codecForAmountString()) .property("currency_specification", codecForCurrencySpecificiation()) .property("currency", codecForString()) + .property("supported_tan_channels", codecForList(codecForEither( + codecForConstString(TanChannel.SMS), + codecForConstString(TanChannel.EMAIL), + ))) .build("TalerCorebankApi.Config"); export const codecForMerchantConfig = @@ -310,9 +318,10 @@ const codecForBalance = (): Codec<TalerCorebankApi.Balance> => const codecForPublicAccount = (): Codec<TalerCorebankApi.PublicAccount> => buildCodecForObject<TalerCorebankApi.PublicAccount>() - .property("account_name", codecForString()) + .property("username", codecForString()) .property("balance", codecForBalance()) .property("payto_uri", codecForPaytoString()) + .property("is_taler_exchange", codecForBoolean()) .build("TalerCorebankApi.PublicAccount"); export const codecForPublicAccountsResponse = @@ -328,6 +337,8 @@ export const codecForAccountMinimalData = .property("debit_threshold", codecForAmountString()) .property("name", codecForString()) .property("username", codecForString()) + .property("is_public", codecForBoolean()) + .property("is_taler_exchange", codecForBoolean()) .build("TalerCorebankApi.AccountMinimalData"); export const codecForListBankAccountsResponse = @@ -344,6 +355,8 @@ export const codecForAccountData = (): Codec<TalerCorebankApi.AccountData> => .property("debit_threshold", codecForAmountString()) .property("contact_data", codecOptional(codecForChallengeContactData())) .property("cashout_payto_uri", codecOptional(codecForPaytoString())) + .property("is_public", codecForBoolean()) + .property("is_taler_exchange", codecForBoolean()) .build("TalerCorebankApi.AccountData"); export const codecForChallengeContactData = @@ -353,6 +366,27 @@ export const codecForChallengeContactData = .property("phone", codecOptional(codecForString())) .build("TalerCorebankApi.ChallengeContactData"); +export const codecForWithdrawalPublicInfo = + (): Codec<TalerCorebankApi.WithdrawalPublicInfo> => + buildCodecForObject<TalerCorebankApi.WithdrawalPublicInfo>() + .property("username", codecForString()) + .property("amount", codecForAmountString()) + .property( + "selected_exchange_account", + codecOptional(codecForPaytoString()), + ) + .property("selected_reserve_pub", codecOptional(codecForString())) + .property( + "status", + codecForEither( + codecForConstString("pending"), + codecForConstString("selected"), + codecForConstString("aborted"), + codecForConstString("confirmed"), + ), + ) + .build("TalerCorebankApi.WithdrawalPublicInfo"); + export const codecForBankAccountTransactionsResponse = (): Codec<TalerCorebankApi.BankAccountTransactionsResponse> => buildCodecForObject<TalerCorebankApi.BankAccountTransactionsResponse>() @@ -380,6 +414,18 @@ export const codecForBankAccountTransactionInfo = .property("date", codecForTimestamp) .build("TalerCorebankApi.BankAccountTransactionInfo"); +export const codecForCreateTransactionResponse = + (): Codec<TalerCorebankApi.CreateTransactionResponse> => + buildCodecForObject<TalerCorebankApi.CreateTransactionResponse>() + .property("row_id", codecForNumber()) + .build("TalerCorebankApi.CreateTransactionResponse"); + +export const codecForRegisterAccountResponse = + (): Codec<TalerCorebankApi.RegisterAccountResponse> => + buildCodecForObject<TalerCorebankApi.RegisterAccountResponse>() + .property("internal_payto_uri", codecForPaytoString()) + .build("TalerCorebankApi.RegisterAccountResponse"); + export const codecForBankAccountCreateWithdrawalResponse = (): Codec<TalerCorebankApi.BankAccountCreateWithdrawalResponse> => buildCodecForObject<TalerCorebankApi.BankAccountCreateWithdrawalResponse>() @@ -387,20 +433,6 @@ export const codecForBankAccountCreateWithdrawalResponse = .property("withdrawal_id", codecForString()) .build("TalerCorebankApi.BankAccountCreateWithdrawalResponse"); -export const codecForBankAccountGetWithdrawalResponse = - (): Codec<TalerCorebankApi.BankAccountGetWithdrawalResponse> => - buildCodecForObject<TalerCorebankApi.BankAccountGetWithdrawalResponse>() - .property("amount", codecForAmountString()) - .property("aborted", codecForBoolean()) - .property("confirmation_done", codecForBoolean()) - .property( - "selected_exchange_account", - codecOptional(codecForPaytoString()), - ) - .property("selected_reserve_pub", codecOptional(codecForString())) - .property("selection_done", codecForBoolean()) - .build("TalerCorebankApi.BankAccountGetWithdrawalResponse"); - export const codecForCashoutPending = (): Codec<TalerCorebankApi.CashoutPending> => buildCodecForObject<TalerCorebankApi.CashoutPending>() @@ -476,7 +508,15 @@ export const codecForCashoutStatusResponse = codecForConstString("confirmed"), ), ) + .property( + "tan_channel", + codecForEither( + codecForConstString(TanChannel.SMS), + codecForConstString(TanChannel.EMAIL), + ), + ) .property("subject", codecForString()) + .property("tan_info", codecForString()) .build("TalerCorebankApi.CashoutStatusResponse"); export const codecForConversionRatesResponse = @@ -534,21 +574,37 @@ export const codecForBankVersion = export const codecForBankWithdrawalOperationStatus = (): Codec<TalerBankIntegrationApi.BankWithdrawalOperationStatus> => buildCodecForObject<TalerBankIntegrationApi.BankWithdrawalOperationStatus>() - .property("aborted", codecForBoolean()) - .property("selection_done", codecForBoolean()) - .property("transfer_done", codecForBoolean()) + .property( + "status", + codecForEither( + codecForConstString("pending"), + codecForConstString("selected"), + codecForConstString("aborted"), + codecForConstString("confirmed"), + ), + ) .property("amount", codecForAmountString()) .property("sender_wire", codecOptional(codecForPaytoString())) .property("suggested_exchange", codecOptional(codecForString())) .property("confirm_transfer_url", codecOptional(codecForURL())) .property("wire_types", codecForList(codecForString())) + .property("selected_reserve_pub", codecOptional(codecForString())) + .property("selected_exchange_account", codecOptional(codecForString())) .build("TalerBankIntegrationApi.BankWithdrawalOperationStatus"); export const codecForBankWithdrawalOperationPostResponse = (): Codec<TalerBankIntegrationApi.BankWithdrawalOperationPostResponse> => buildCodecForObject<TalerBankIntegrationApi.BankWithdrawalOperationPostResponse>() + .property( + "status", + codecForEither( + codecForConstString("pending"), + codecForConstString("selected"), + codecForConstString("aborted"), + codecForConstString("confirmed"), + ), + ) .property("confirm_transfer_url", codecOptional(codecForURL())) - .property("transfer_done", codecForBoolean()) .build("TalerBankIntegrationApi.BankWithdrawalOperationPostResponse"); export const codecForMerchantIncomingHistory = @@ -755,20 +811,26 @@ export const codecForConversionInfo = .property("cashin_fee", codecForAmountString()) .property("cashin_min_amount", codecForAmountString()) .property("cashin_ratio", codecForDecimalNumber()) - .property("cashin_rounding_mode", codecForEither( - codecForConstString("zero"), - codecForConstString("up"), - codecForConstString("nearest") - )) + .property( + "cashin_rounding_mode", + codecForEither( + codecForConstString("zero"), + codecForConstString("up"), + codecForConstString("nearest"), + ), + ) .property("cashin_tiny_amount", codecForAmountString()) .property("cashout_fee", codecForAmountString()) .property("cashout_min_amount", codecForAmountString()) .property("cashout_ratio", codecForDecimalNumber()) - .property("cashout_rounding_mode", codecForEither( - codecForConstString("zero"), - codecForConstString("up"), - codecForConstString("nearest") - )) + .property( + "cashout_rounding_mode", + codecForEither( + codecForConstString("zero"), + codecForConstString("up"), + codecForConstString("nearest"), + ), + ) .property("cashout_tiny_amount", codecForAmountString()) .build("ConversionBankConfig.ConversionInfo"); @@ -786,7 +848,7 @@ export const codecForConversionBankConfig = .property("fiat_currency_specification", codecForCurrencySpecificiation()) .property("conversion_rate", codecOptional(codecForConversionInfo())) - .build("ConversionBankConfig.IntegrationConfig") + .build("ConversionBankConfig.IntegrationConfig"); // export const codecFor = // (): Codec<TalerWireGatewayApi.PublicAccountsResponse> => @@ -827,15 +889,20 @@ interface CSCoinEnvelope { // a 256-bit nonce, converted to Crockford Base32. type DenominationBlindingKeyP = string; -const codecForURL = codecForString -const codecForLibtoolVersion = codecForString -const codecForCurrencyName = codecForString -const codecForDecimalNumber = codecForString +const codecForURL = codecForString; +const codecForLibtoolVersion = codecForString; +const codecForCurrencyName = codecForString; +const codecForDecimalNumber = codecForString; enum TanChannel { SMS = "sms", EMAIL = "email", } +export type WithdrawalOperationStatus = + | "pending" + | "selected" + | "aborted" + | "confirmed"; export namespace TalerWireGatewayApi { export interface TransferResponse { @@ -882,7 +949,9 @@ export namespace TalerWireGatewayApi { // This must be one of the exchange's bank accounts. // Credit account is shared by all incoming transactions // as per the nature of the request. - credit_account: PaytoString; + + // undefined if incoming transaction is empty + credit_account?: PaytoString; } // Union discriminated by the "type" field. @@ -943,7 +1012,9 @@ export namespace TalerWireGatewayApi { // This must be one of the exchange's bank accounts. // Credit account is shared by all incoming transactions // as per the nature of the request. - debit_account: PaytoString; + + // undefined if outgoing transactions is empty + debit_account?: PaytoString; } export interface OutgoingBankTransaction { @@ -1085,7 +1156,7 @@ export namespace TalerBankConversionApi { // Extra conversion rate information. // Only present if server opts in to report the static conversion rate. - conversion_rate?: ConversionInfo + conversion_rate?: ConversionInfo; } export interface CashinConversionResponse { @@ -1105,6 +1176,40 @@ export namespace TalerBankConversionApi { // bank account, according to 'amount_debit'. amount_credit: AmountString; } + + export type RoundingMode = "zero" | "up" | "nearest"; + + export interface ConversionRate { + // Exchange rate to buy regional currency from fiat + cashin_ratio: DecimalNumber; + + // Fee to subtract after applying the cashin ratio. + cashin_fee: AmountString; + + // Minimum amount authorised for cashin, in fiat before conversion + cashin_min_amount: AmountString; + + // Smallest possible regional amount, converted amount is rounded to this amount + cashin_tiny_amount: AmountString; + + // Rounding mode used during cashin conversion + cashin_rounding_mode: RoundingMode; + + // Exchange rate to sell regional currency for fiat + cashout_ratio: DecimalNumber; + + // Fee to subtract after applying the cashout ratio. + cashout_fee: AmountString; + + // Minimum amount authorised for cashout, in regional before conversion + cashout_min_amount: AmountString; + + // Smallest possible fiat amount, converted amount is rounded to this amount + cashout_tiny_amount: AmountString; + + // Rounding mode used during cashout conversion + cashout_rounding_mode: RoundingMode; + } } export namespace TalerBankIntegrationApi { export interface BankVersion { @@ -1124,17 +1229,12 @@ export namespace TalerBankIntegrationApi { } export interface BankWithdrawalOperationStatus { - // Indicates whether the withdrawal was aborted. - aborted: boolean; - - // Has the wallet selected parameters for the withdrawal operation - // (exchange and reserve public key) and successfully sent it - // to the bank? - selection_done: boolean; - - // The transfer has been confirmed and registered by the bank. - // Does not guarantee that the funds have arrived at the exchange already. - transfer_done: boolean; + // Current status of the operation + // pending: the operation is pending parameters selection (exchange and reserve public key) + // selected: the operations has been selected and is pending confirmation + // aborted: the operation has been aborted + // confirmed: the transfer has been confirmed and registered by the bank + status: WithdrawalOperationStatus; // Amount that will be withdrawn with this operation // (raw amount without fee considerations). @@ -1154,6 +1254,14 @@ export namespace TalerBankIntegrationApi { // Wire transfer types supported by the bank. wire_types: string[]; + + // Reserve public key selected by the exchange, + // only non-null if status is selected or confirmed. + selected_reserve_pub?: string; + + // Exchange account selected by the wallet + // only non-null if status is selected or confirmed. + selected_exchange_account?: string; } export interface BankWithdrawalOperationPostRequest { @@ -1165,14 +1273,17 @@ export namespace TalerBankIntegrationApi { } export interface BankWithdrawalOperationPostResponse { - // The transfer has been confirmed and registered by the bank. - // Does not guarantee that the funds have arrived at the exchange already. - transfer_done: boolean; + // Current status of the operation + // pending: the operation is pending parameters selection (exchange and reserve public key) + // selected: the operations has been selected and is pending confirmation + // aborted: the operation has been aborted + // confirmed: the transfer has been confirmed and registered by the bank + status: Omit<"pending", WithdrawalOperationStatus>; // URL that the user needs to navigate to in order to // complete some final confirmation (e.g. 2FA). // - // Only applicable when transfer_done is false. + // Only applicable when status is selected. // It may contain withdrawal operation id confirm_transfer_url?: string; } @@ -1184,7 +1295,10 @@ export namespace TalerCorebankApi { // The format is "current:revision:age". version: string; - currency: String; + currency: string; + + // How the bank SPA should render this currency. + currency_specification: CurrencySpecification; // Name of the API. name: "taler-bank-integration"; @@ -1209,11 +1323,25 @@ export namespace TalerCorebankApi { // If 'false' only the admin can delete accounts allow_deletions: boolean; + // If 'true' anyone can edit their name + // If 'false' only admin can + allow_edit_name: boolean; + + // If 'true' anyone can edit their cashout account + // If 'false' only the admin + allow_edit_cashout_payto_uri: boolean; + + // Default debt limit for newly created accounts + default_debit_threshold: AmountString; + // Currency used by this bank. currency: string; // How the bank SPA should render this currency. currency_specification: CurrencySpecification; + + // TAN channels supported by the server + supported_tan_channels: TanChannel[]; } export interface BankAccountCreateWithdrawalRequest { @@ -1227,29 +1355,28 @@ export namespace TalerCorebankApi { // URI that can be passed to the wallet to initiate the withdrawal. taler_withdraw_uri: TalerActionString; } - export interface BankAccountGetWithdrawalResponse { - // Amount that will be withdrawn with this withdrawal operation. - amount: AmountString; - - // Was the withdrawal aborted? - aborted: boolean; + export interface WithdrawalPublicInfo { + // Current status of the operation + // pending: the operation is pending parameters selection (exchange and reserve public key) + // selected: the operations has been selected and is pending confirmation + // aborted: the operation has been aborted + // confirmed: the transfer has been confirmed and registered by the bank + status: WithdrawalOperationStatus; - // Has the withdrawal been confirmed by the bank? - // The wire transfer for a withdrawal is only executed once - // both confirmation_done is true and selection_done is true. - confirmation_done: boolean; + // Amount that will be withdrawn with this operation + // (raw amount without fee considerations). + amount: AmountString; - // Did the wallet select reserve details? - selection_done: boolean; + // Account username + username: string; // Reserve public key selected by the exchange, - // only non-null if selection_done is true. - selected_reserve_pub: string | undefined; + // only non-null if status is selected or confirmed. + selected_reserve_pub?: string; - // Exchange account selected by the wallet, or by the bank - // (with the default exchange) in case the wallet did not provide one - // through the Integration API. - selected_exchange_account: PaytoString | undefined; + // Exchange account selected by the wallet + // only non-null if status is selected or confirmed. + selected_exchange_account?: PaytoString; } export interface BankAccountTransactionsResponse { @@ -1271,7 +1398,7 @@ export namespace TalerCorebankApi { date: Timestamp; } - export interface CreateBankAccountTransactionCreate { + export interface CreateTransactionRequest { // Address in the Payto format of the wire transfer receiver. // It needs at least the 'message' query string parameter. payto_uri: PaytoString; @@ -1283,6 +1410,16 @@ export namespace TalerCorebankApi { amount?: AmountString; } + export interface CreateTransactionResponse { + // ID identifying the transaction being created + row_id: Integer; + } + + export interface RegisterAccountResponse { + // Internal payto URI of this bank account. + internal_payto_uri: PaytoString; + } + export interface RegisterAccountRequest { // Username username: string; @@ -1309,19 +1446,23 @@ export namespace TalerCorebankApi { // If missing, cashouts will fail. // In the future, might be used for other transactions // as well. - challenge_contact_data?: ChallengeContactData; + contact_data?: ChallengeContactData; - // 'payto' address pointing a bank account - // external to the libeufin-bank. + // 'payto' address of a fiat bank account. // Payments will be sent to this bank account - // when the user wants to convert the local currency - // back to fiat currency outside libeufin-bank. + // when the user wants to convert the regional currency + // back to fiat currency outside bank. cashout_payto_uri?: PaytoString; // Internal payto URI of this bank account. // Used mostly for testing. - internal_payto_uri?: PaytoString; + payto_uri?: PaytoString; + + // If present, set the max debit allowed for this user + // Only admin can change this property. + debit_threshold?: AmountString; } + export interface ChallengeContactData { // E-Mail address email?: EmailAddress; @@ -1336,22 +1477,22 @@ export namespace TalerCorebankApi { // If missing, cashouts will fail. // In the future, might be used for other transactions // as well. - challenge_contact_data?: ChallengeContactData; + // Only admin can change this property. + contact_data?: ChallengeContactData; - // 'payto' address pointing a bank account - // external to the libeufin-bank. + // 'payto' URI of a fiat bank account. // Payments will be sent to this bank account - // when the user wants to convert the local currency - // back to fiat currency outside libeufin-bank. + // when the user wants to convert the regional currency + // back to fiat currency outside bank. + // Only admin can change this property if not allowed in config cashout_payto_uri?: PaytoString; - // Legal name associated with $username. - // When missing, the old name is kept. + // If present, change the legal name associated with $username. + // Only admin can change this property if not allowed in config name?: string; - // If present, change the is_exchange configuration. - // See RegisterAccountRequest - is_taler_exchange?: boolean; + // Make this account visible to anyone? + is_public?: boolean; // If present, change the max debit allowed for this user // Only admin can change this property. @@ -1370,13 +1511,17 @@ export namespace TalerCorebankApi { public_accounts: PublicAccount[]; } export interface PublicAccount { - payto_uri: PaytoString; + // Username of the account + username: string; + // Internal payto URI of this bank account. + payto_uri: string; + + // Current balance of the account balance: Balance; - // The account name (=username) of the - // libeufin-bank account. - account_name: string; + // Is this a taler exchange account? + is_taler_exchange: boolean; } export interface ListBankAccountsResponse { @@ -1398,6 +1543,12 @@ export namespace TalerCorebankApi { // Number indicating the max debit allowed for the requesting user. debit_threshold: AmountString; + + // Is this account visible to anyone? + is_public: boolean; + + // Is this a taler exchange account? + is_taler_exchange: boolean; } export interface AccountData { @@ -1422,6 +1573,12 @@ export namespace TalerCorebankApi { // that never cashouts. Registering these accounts can // be done via the access API. cashout_payto_uri?: PaytoString; + + // Is this account visible to anyone? + is_public: boolean; + + // Is this a taler exchange account? + is_taler_exchange: boolean; } export interface CashoutRequest { @@ -1512,6 +1669,14 @@ export namespace TalerCorebankApi { // Time when the cashout was confirmed via its TAN. // Missing when the operation wasn't confirmed yet. confirmation_time?: Timestamp; + + // Channel of the last successful transmission of the TAN challenge. + // Missing when all transmissions failed. + tan_channel?: TanChannel; + + // Info of the last successful transmission of the TAN challenge. + // Missing when all transmissions failed. + tan_info?: string; } export interface ConversionRatesResponse { diff --git a/packages/taler-util/src/http-client/utils.ts b/packages/taler-util/src/http-client/utils.ts @@ -1,6 +1,4 @@ import { base64FromArrayBuffer } from "../base64.js"; -import { HttpResponse, readSuccessResponseJsonOrThrow, readTalerErrorResponse } from "../http-common.js"; -import { Codec, TalerError, TalerErrorCode, TalerErrorDetail } from "../index.js"; import { stringToBytes } from "../taler-crypto.js"; import { AccessToken, PaginationParams } from "./types.js"; diff --git a/packages/taler-util/src/http-common.ts b/packages/taler-util/src/http-common.ts @@ -155,6 +155,7 @@ export async function readTalerErrorResponse( requestUrl: httpResponse.requestUrl, requestMethod: httpResponse.requestMethod, httpStatusCode: httpResponse.status, + contentType: contentType || "<null>", }, "Error response did not even contain JSON. The request URL might be wrong or the service might be unavailable.", ); diff --git a/packages/taler-util/src/http-impl.qtart.ts b/packages/taler-util/src/http-impl.qtart.ts @@ -97,10 +97,24 @@ export class HttpLibImpl implements HttpRequestLibrary { data, headers: headersList, }); + + const headers: Headers = new Headers(); + + if (res.headers) { + for (const headerStr of res.headers) { + const splitPos = headerStr.indexOf(":"); + if (splitPos < 0) { + continue; + } + const headerName = headerStr.slice(0, splitPos).trim().toLowerCase(); + const headerValue = headerStr.slice(splitPos + 1).trim(); + headers.set(headerName, headerValue); + } + } + return { requestMethod: method, - // FIXME: We don't return headers! - headers: new Headers(), + headers, async bytes() { return res.data; }, diff --git a/packages/taler-util/src/notifications.ts b/packages/taler-util/src/notifications.ts @@ -23,15 +23,14 @@ * Imports. */ import { TransactionState } from "./transactions-types.js"; -import { TalerErrorDetail } from "./wallet-types.js"; +import { ExchangeEntryState, TalerErrorDetail } from "./wallet-types.js"; export enum NotificationType { BalanceChange = "balance-change", - ExchangeOperationError = "exchange-operation-error", - ExchangeAdded = "exchange-added", BackupOperationError = "backup-error", PendingOperationProcessed = "pending-operation-processed", TransactionStateTransition = "transaction-state-transition", + ExchangeStateTransition = "exchange-state-transition", } export interface ErrorInfoSummary { @@ -59,17 +58,41 @@ export interface TransactionStateTransitionNotification { experimentalUserData?: any; } -export interface ExchangeAddedNotification { - type: NotificationType.ExchangeAdded; +export interface ExchangeStateTransitionNotification { + type: NotificationType.ExchangeStateTransition; + /** + * Identification of the exchange entry that this + * notification is about. + */ + exchangeBaseUrl: string; + + /** + * If missing, the notification means that + * the exchange entry is newly created. + */ + oldExchangeState?: ExchangeEntryState; + + /** + * New state of the exchange. + */ + newExchangeState: ExchangeEntryState; + + /** + * Summary of the error that occurred when trying to update the exchange entry, + * if applicable. + */ + errorInfo?: ErrorInfoSummary; } export interface BalanceChangeNotification { type: NotificationType.BalanceChange; -} -export interface ExchangeOperationErrorNotification { - type: NotificationType.ExchangeOperationError; - error: TalerErrorDetail; + /** + * Transaction ID of the transaction that caused the balance update. + * + * Only used as a hint for debugging, should not be relied upon by clients. + */ + hintTransactionId: string; } export interface BackupOperationErrorNotification { @@ -80,12 +103,12 @@ export interface BackupOperationErrorNotification { export interface PendingOperationProcessedNotification { type: NotificationType.PendingOperationProcessed; id: string; + taskResultType: string; } export type WalletNotification = | BalanceChangeNotification | BackupOperationErrorNotification - | ExchangeAddedNotification - | ExchangeOperationErrorNotification + | ExchangeStateTransitionNotification | PendingOperationProcessedNotification | TransactionStateTransitionNotification; diff --git a/packages/taler-util/src/qtart.ts b/packages/taler-util/src/qtart.ts @@ -6,6 +6,7 @@ import * as _qjsStdImp from "std"; export interface QjsHttpResp { status: number; data: ArrayBuffer; + headers?: string[]; } export interface QjsHttpOptions { diff --git a/packages/taler-util/src/taler-crypto.ts b/packages/taler-util/src/taler-crypto.ts @@ -844,7 +844,8 @@ export function hashDenomPub(pub: DenominationPubKey): Uint8Array { return hash(uint8ArrayBuf); } else { throw Error( - `unsupported cipher (${(pub as DenominationPubKey).cipher + `unsupported cipher (${ + (pub as DenominationPubKey).cipher }), unable to hash`, ); } @@ -993,6 +994,7 @@ export enum TalerSignaturePurpose { WALLET_ACCOUNT_MERGE = 1214, WALLET_PURSE_ECONTRACT = 1216, WALLET_PURSE_DELETE = 1220, + WALLET_COIN_HISTORY = 1209, EXCHANGE_CONFIRM_RECOUP = 1039, EXCHANGE_CONFIRM_RECOUP_REFRESH = 1041, TALER_SIGNATURE_AML_DECISION = 1350, @@ -1022,7 +1024,7 @@ export enum WalletAccountMergeFlags { export class SignaturePurposeBuilder { private chunks: Uint8Array[] = []; - constructor(private purposeNum: number) { } + constructor(private purposeNum: number) {} put(bytes: Uint8Array): SignaturePurposeBuilder { this.chunks.push(Uint8Array.from(bytes)); diff --git a/packages/taler-util/src/taler-error-codes.ts b/packages/taler-util/src/taler-error-codes.ts @@ -3473,6 +3473,22 @@ export enum TalerErrorCode { /** + * A non-admin user has tried to change their cashout account. + * Returned with an HTTP status code of #MHD_HTTP_CONFLICT (409). + * (A value of 0 indicates that the error is generated client-side). + */ + BANK_NON_ADMIN_PATCH_CASHOUT = 5140, + + + /** + * A non-admin user has tried to change their contact info. + * Returned with an HTTP status code of #MHD_HTTP_CONFLICT (409). + * (A value of 0 indicates that the error is generated client-side). + */ + BANK_NON_ADMIN_PATCH_CONTACT = 5141, + + + /** * The sync service failed find the account in its database. * Returned with an HTTP status code of #MHD_HTTP_NOT_FOUND (404). * (A value of 0 indicates that the error is generated client-side). diff --git a/packages/taler-util/src/taler-types.ts b/packages/taler-util/src/taler-types.ts @@ -38,6 +38,7 @@ import { codecForMap, codecForNumber, codecForString, + codecForStringURL, codecOptional, } from "./codec.js"; import { strcmp } from "./helpers.js"; @@ -2372,7 +2373,7 @@ export interface ExchangeWireAccount { export const codecForExchangeWireAccount = (): Codec<ExchangeWireAccount> => buildCodecForObject<ExchangeWireAccount>() - .property("conversion_url", codecOptional(codecForString())) + .property("conversion_url", codecOptional(codecForStringURL())) .property("credit_restrictions", codecForList(codecForAny())) .property("debit_restrictions", codecForList(codecForAny())) .property("master_sig", codecForString()) diff --git a/packages/taler-util/src/taleruri.test.ts b/packages/taler-util/src/taleruri.test.ts @@ -16,6 +16,10 @@ import test from "ava"; import { + parseAuditorUri, + parseDevExperimentUri, + parseExchangeUri, + parsePayPullUri, parsePayPushUri, parsePayTemplateUri, parsePayUri, @@ -24,23 +28,63 @@ import { parseRewardUri, parseWithdrawExchangeUri, parseWithdrawUri, + stringifyAuditorUri, + stringifyDevExperimentUri, + stringifyExchangeUri, + stringifyPayPullUri, stringifyPayPushUri, + stringifyPayTemplateUri, stringifyPayUri, + stringifyRefundUri, stringifyRestoreUri, + stringifyRewardUri, stringifyWithdrawExchange, + stringifyWithdrawUri, } from "./taleruri.js"; import { AmountString } from "./taler-types.js"; -test("taler pay url parsing: wrong scheme", (t) => { - const url1 = "talerfoo://"; - const r1 = parsePayUri(url1); - t.is(r1, undefined); - const url2 = "taler://refund/a/b/c/d/e/f"; - const r2 = parsePayUri(url2); - t.is(r2, undefined); +/** + * 5.1 action: withdraw https://lsd.gnunet.org/lsd0006/#name-action-withdraw + */ + +test("taler withdraw uri parsing", (t) => { + const url1 = "taler://withdraw/bank.example.com/12345"; + const r1 = parseWithdrawUri(url1); + if (!r1) { + t.fail(); + return; + } + t.is(r1.withdrawalOperationId, "12345"); + t.is(r1.bankIntegrationApiBaseUrl, "https://bank.example.com/"); }); +test("taler withdraw uri parsing (http)", (t) => { + const url1 = "taler+http://withdraw/bank.example.com/12345"; + const r1 = parseWithdrawUri(url1); + if (!r1) { + t.fail(); + return; + } + t.is(r1.withdrawalOperationId, "12345"); + t.is(r1.bankIntegrationApiBaseUrl, "http://bank.example.com/"); +}); + +test("taler withdraw URI (stringify)", (t) => { + const url = stringifyWithdrawUri({ + bankIntegrationApiBaseUrl: "https://bank.taler.test/integration-api/", + withdrawalOperationId: "123" + }); + t.deepEqual( + url, + "taler://withdraw/bank.taler.test/integration-api/123", + ); +}); + + +/** + * 5.2 action: pay https://lsd.gnunet.org/lsd0006/#name-action-pay + */ test("taler pay url parsing: defaults", (t) => { const url1 = "taler://pay/example.com/myorder/"; const r1 = parsePayUri(url1); @@ -84,17 +128,6 @@ test("taler pay url parsing (claim token)", (t) => { t.is(r1.claimToken, "ASDF"); }); -test("taler refund uri parsing: non-https #1", (t) => { - const url1 = "taler+http://refund/example.com/myorder/"; - const r1 = parseRefundUri(url1); - if (!r1) { - t.fail(); - return; - } - t.is(r1.merchantBaseUrl, "http://example.com/"); - t.is(r1.orderId, "myorder"); -}); - test("taler pay uri parsing: non-https", (t) => { const url1 = "taler+http://pay/example.com/myorder/"; const r1 = parsePayUri(url1); @@ -116,28 +149,55 @@ test("taler pay uri parsing: missing session component", (t) => { t.pass(); }); -test("taler withdraw uri parsing", (t) => { - const url1 = "taler://withdraw/bank.example.com/12345"; - const r1 = parseWithdrawUri(url1); - if (!r1) { - t.fail(); - return; - } - t.is(r1.withdrawalOperationId, "12345"); - t.is(r1.bankIntegrationApiBaseUrl, "https://bank.example.com/"); +test("taler pay URI (stringify)", (t) => { + const url1 = stringifyPayUri({ + merchantBaseUrl: "http://localhost:123/", + orderId: "foo", + sessionId: "", + }); + t.deepEqual(url1, "taler+http://pay/localhost:123/foo/"); + + const url2 = stringifyPayUri({ + merchantBaseUrl: "http://localhost:123/", + orderId: "foo", + sessionId: "bla", + }); + t.deepEqual(url2, "taler+http://pay/localhost:123/foo/bla"); }); -test("taler withdraw uri parsing (http)", (t) => { - const url1 = "taler+http://withdraw/bank.example.com/12345"; - const r1 = parseWithdrawUri(url1); +test("taler pay URI (stringify with https)", (t) => { + const url1 = stringifyPayUri({ + merchantBaseUrl: "https://localhost:123/", + orderId: "foo", + sessionId: "", + }); + t.deepEqual(url1, "taler://pay/localhost:123/foo/"); + + const url2 = stringifyPayUri({ + merchantBaseUrl: "https://localhost/", + orderId: "foo", + sessionId: "bla", + noncePriv: "123", + }); + t.deepEqual(url2, "taler://pay/localhost/foo/bla?n=123"); +}); + +/** + * 5.3 action: refund https://lsd.gnunet.org/lsd0006/#name-action-refund + */ + +test("taler refund uri parsing: non-https #1", (t) => { + const url1 = "taler+http://refund/example.com/myorder/"; + const r1 = parseRefundUri(url1); if (!r1) { t.fail(); return; } - t.is(r1.withdrawalOperationId, "12345"); - t.is(r1.bankIntegrationApiBaseUrl, "http://bank.example.com/"); + t.is(r1.merchantBaseUrl, "http://example.com/"); + t.is(r1.orderId, "myorder"); }); + test("taler refund uri parsing", (t) => { const url1 = "taler://refund/merchant.example.com/1234/"; const r1 = parseRefundUri(url1); @@ -160,6 +220,23 @@ test("taler refund uri parsing with instance", (t) => { t.is(r1.merchantBaseUrl, "https://merchant.example.com/instances/myinst/"); }); +test("taler refund URI (stringify)", (t) => { + const url = stringifyRefundUri({ + merchantBaseUrl: "https://merchant.test/instance/pepe/", + orderId:"123" + }); + t.deepEqual( + url, + "taler://refund/merchant.test/instance/pepe/123/", + ); +}); + + +/** + * 5.4 action: reward https://lsd.gnunet.org/lsd0006/#name-action-tip + */ + + test("taler reward pickup uri", (t) => { const url1 = "taler://reward/merchant.example.com/tipid"; const r1 = parseRewardUri(url1); @@ -192,6 +269,22 @@ test("taler reward pickup uri with instance and prefix", (t) => { t.is(r1.merchantRewardId, "tipid"); }); +test("taler reward URI (stringify)", (t) => { + const url = stringifyRewardUri({ + merchantBaseUrl: "https://merchant.test/instance/pepe/", + merchantRewardId: "123" + }); + t.deepEqual( + url, + "taler://reward/merchant.test/instance/pepe/123/", + ); +}); + + +/** + * 5.5 action: pay-push https://lsd.gnunet.org/lsd0006/#name-action-pay-push + */ + test("taler peer to peer push URI", (t) => { const url1 = "taler://pay-push/exch.example.com/foo"; const r1 = parsePayPushUri(url1); @@ -232,39 +325,60 @@ test("taler peer to peer push URI (stringify)", (t) => { }); t.deepEqual(url, "taler://pay-push/foo.example.com/bla/123"); }); -test("taler pay URI (stringify)", (t) => { - const url1 = stringifyPayUri({ - merchantBaseUrl: "http://localhost:123/", - orderId: "foo", - sessionId: "", - }); - t.deepEqual(url1, "taler+http://pay/localhost:123/foo/"); - const url2 = stringifyPayUri({ - merchantBaseUrl: "http://localhost:123/", - orderId: "foo", - sessionId: "bla", - }); - t.deepEqual(url2, "taler+http://pay/localhost:123/foo/bla"); + +/** + * 5.6 action: pay-pull https://lsd.gnunet.org/lsd0006/#name-action-pay-pull + */ + +test("taler peer to peer pull URI", (t) => { + const url1 = "taler://pay-pull/exch.example.com/foo"; + const r1 = parsePayPullUri(url1); + if (!r1) { + t.fail(); + return; + } + t.is(r1.exchangeBaseUrl, "https://exch.example.com/"); + t.is(r1.contractPriv, "foo"); }); -test("taler pay URI (stringify with https)", (t) => { - const url1 = stringifyPayUri({ - merchantBaseUrl: "https://localhost:123/", - orderId: "foo", - sessionId: "", - }); - t.deepEqual(url1, "taler://pay/localhost:123/foo/"); +test("taler peer to peer pull URI (path)", (t) => { + const url1 = "taler://pay-pull/exch.example.com:123/bla/foo"; + const r1 = parsePayPullUri(url1); + if (!r1) { + t.fail(); + return; + } + t.is(r1.exchangeBaseUrl, "https://exch.example.com:123/bla/"); + t.is(r1.contractPriv, "foo"); +}); - const url2 = stringifyPayUri({ - merchantBaseUrl: "https://localhost/", - orderId: "foo", - sessionId: "bla", - noncePriv: "123", +test("taler peer to peer pull URI (http)", (t) => { + const url1 = "taler+http://pay-pull/exch.example.com:123/bla/foo"; + const r1 = parsePayPullUri(url1); + if (!r1) { + t.fail(); + return; + } + t.is(r1.exchangeBaseUrl, "http://exch.example.com:123/bla/"); + t.is(r1.contractPriv, "foo"); +}); + +test("taler peer to peer pull URI (stringify)", (t) => { + const url = stringifyPayPullUri({ + exchangeBaseUrl: "https://foo.example.com/bla/", + contractPriv: "123", }); - t.deepEqual(url2, "taler://pay/localhost/foo/bla?n=123"); + t.deepEqual(url, "taler://pay-pull/foo.example.com/bla/123"); }); + + +/** + * 5.7 action: pay-template https://lsd.gnunet.org/lsd0006/#name-action-pay-template + */ + + test("taler pay template URI (parsing)", (t) => { const url1 = "taler://pay-template/merchant.example.com/FEGHYJY48FEGU6WETYIOIDEDE2QW3OCZVY?amount=KUDOS:5"; @@ -291,6 +405,72 @@ test("taler pay template URI (parsing, http with port)", (t) => { t.deepEqual(r1.templateParams.amount, "KUDOS:5"); }); +test("taler pay template URI (stringify)", (t) => { + const url1 = stringifyPayTemplateUri({ + merchantBaseUrl: "http://merchant.example.com:1234/", + templateId: "FEGHYJY48FEGU6WETYIOIDEDE2QW3OCZVY", + templateParams: { + amount: "KUDOS:5" + }, + }); + t.deepEqual(url1, "taler+http://pay-template/merchant.example.com:1234/FEGHYJY48FEGU6WETYIOIDEDE2QW3OCZVY?amount=KUDOS%3A5"); +}); + + +/** + * 5.8 action: exchange https://lsd.gnunet.org/lsd0006/#name-action-exchange + */ + +test("taler exchange URI (parsing)", (t) => { + const url1 = + "taler://exchange/exchange.test/123"; + const r1 = parseExchangeUri(url1); + if (!r1) { + t.fail(); + return; + } + t.deepEqual(r1.exchangeBaseUrl, "https://exchange.test/"); + t.deepEqual(r1.exchangePub, "123"); +}); + +test("taler exchange URI (stringify)", (t) => { + const url1 = stringifyExchangeUri({ + exchangeBaseUrl: "https://exchange.test", + exchangePub: "123" + }); + t.deepEqual(url1, "taler://exchange/exchange.test/123"); +}); + + +/** + * 5.9 action: auditor https://lsd.gnunet.org/lsd0006/#name-action-auditor + */ + + + +test("taler auditor URI (parsing)", (t) => { + const url1 = + "taler://auditor/auditor.test/123"; + const r1 = parseAuditorUri(url1); + if (!r1) { + t.fail(); + return; + } + t.deepEqual(r1.auditorBaseUrl, "https://auditor.test/"); + t.deepEqual(r1.auditorPub, "123"); +}); + +test("taler auditor URI (stringify)", (t) => { + const url1 = stringifyAuditorUri({ + auditorBaseUrl: "https://auditor.test", + auditorPub: "123" + }); + t.deepEqual(url1, "taler://auditor/auditor.test/123"); +}); + +/** + * 5.10 action: restore https://lsd.gnunet.org/lsd0006/#name-action-restore + */ test("taler restore URI (parsing, http with port)", (t) => { const r1 = parseRestoreUri( "taler+http://restore/GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0/prov1.example.com,prov2.example.com:123", @@ -333,6 +513,35 @@ test("taler restore URI (stringify)", (t) => { ); }); + + +/** + * 5.11 action: dev-experiment https://lsd.gnunet.org/lsd0006/#name-action-dev-experiment + */ + +test("taler dev exp URI (parsing)", (t) => { + const url1 = + "taler://dev-experiment/123"; + const r1 = parseDevExperimentUri(url1); + if (!r1) { + t.fail(); + return; + } + t.deepEqual(r1.devExperimentId, "123"); +}); + +test("taler dev exp URI (stringify)", (t) => { + const url1 = stringifyDevExperimentUri({ + devExperimentId: "123" + }); + t.deepEqual(url1, "taler://dev-experiment/123"); +}); + + +/** + * 5.12 action: withdraw-exchange https://lsd.gnunet.org/lsd0006/#name-action-withdraw-exchange + */ + test("taler withdraw exchange URI (parse)", (t) => { const r1 = parseWithdrawExchangeUri( "taler://withdraw-exchange/exchange.demo.taler.net/someroot/GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0?a=KUDOS%3A2", @@ -371,3 +580,22 @@ test("taler withdraw exchange URI with amount (stringify)", (t) => { "taler://withdraw-exchange/exchange.demo.taler.net/GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0?a=KUDOS%3A19", ); }); + + +/** + * wrong uris + */ +test("taler pay url parsing: wrong scheme", (t) => { + const url1 = "talerfoo://"; + const r1 = parsePayUri(url1); + t.is(r1, undefined); + + const url2 = "taler://refund/a/b/c/d/e/f"; + const r2 = parsePayUri(url2); + t.is(r2, undefined); +}); + + + + + diff --git a/packages/taler-util/src/taleruri.ts b/packages/taler-util/src/taleruri.ts @@ -719,14 +719,14 @@ export function stringifyRefundUri({ orderId, }: Omit<RefundUriResult, "type">): string { const { proto, path } = getUrlInfo(merchantBaseUrl); - return `${proto}://refund/${path}${orderId}`; + return `${proto}://refund/${path}${orderId}/`; } export function stringifyRewardUri({ merchantBaseUrl, merchantRewardId, }: Omit<RewardUriResult, "type">): string { const { proto, path } = getUrlInfo(merchantBaseUrl); - return `${proto}://reward/${path}${merchantRewardId}`; + return `${proto}://reward/${path}${merchantRewardId}/`; } export function stringifyExchangeUri({ diff --git a/packages/taler-util/src/transactions-types.ts b/packages/taler-util/src/transactions-types.ts @@ -51,7 +51,7 @@ import { TalerErrorDetail, TransactionIdStr, TransactionStateFilter, - WithdrawalAccountInfo, + WithdrawalExchangeAccountDetails, } from "./wallet-types.js"; export interface TransactionsRequest { @@ -121,6 +121,7 @@ export enum TransactionMinorState { CheckRefund = "check-refund", CreatePurse = "create-purse", DeletePurse = "delete-purse", + RefreshExpired = "refresh-expired", Ready = "ready", Merge = "merge", Repurchase = "repurchase", @@ -243,7 +244,7 @@ interface WithdrawalDetailsForManualTransfer { */ exchangePaytoUris: string[]; - exchangeCreditAccounts?: WithdrawalAccountInfo[]; + exchangeCreditAccountDetails?: WithdrawalExchangeAccountDetails[]; // Public key of the reserve reservePub: string; @@ -277,6 +278,8 @@ interface WithdrawalDetailsForTalerBankIntegrationApi { * Is the reserve ready for withdrawal? */ reserveIsReady: boolean; + + exchangeCreditAccountDetails?: WithdrawalExchangeAccountDetails[]; } /** diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts @@ -1030,6 +1030,7 @@ export enum RefreshReason { AbortPay = "abort-pay", AbortDeposit = "abort-deposit", AbortPeerPushDebit = "abort-peer-push-debit", + AbortPeerPullDebit = "abort-peer-pull-debit", Recoup = "recoup", BackupRestored = "backup-restored", Scheduled = "scheduled", @@ -1087,13 +1088,27 @@ export interface ExchangeDetailedResponse { export interface WalletCoreVersion { /** - * @deprecated + * Wallet-core protocol version supported by this implementation + * of the API ("server" version). */ - hash: string | undefined; version: string; exchange: string; merchant: string; + + bankIntegrationApiRange: string; + bankConversionApiRange: string; + corebankApiRange: string; + + /** + * @deprecated as bank was split into multiple APIs withs separate versioning + */ bank: string; + + /** + * @deprecated + */ + hash: string | undefined; + /** * @deprecated will be removed */ @@ -1288,12 +1303,11 @@ export enum ExchangeEntryStatus { export enum ExchangeUpdateStatus { Initial = "initial", - InitialUpdate = "initial(update)", + InitialUpdate = "initial-update", Suspended = "suspended", - Failed = "failed", - OutdatedUpdate = "outdated(update)", + UnavailableUpdate = "unavailable-update", Ready = "ready", - ReadyUpdate = "ready(update)", + ReadyUpdate = "ready-update", } export interface OperationErrorInfo { @@ -1304,7 +1318,9 @@ export interface ShortExchangeListItem { exchangeBaseUrl: string; } -// FIXME: This should probably include some error status. +/** + * Info about an exchange entry in the wallet. + */ export interface ExchangeListItem { exchangeBaseUrl: string; currency: string | undefined; @@ -1314,6 +1330,8 @@ export interface ExchangeListItem { exchangeUpdateStatus: ExchangeUpdateStatus; ageRestrictionOptions: number[]; + scopeInfo: ScopeInfo | undefined; + /** * Information about the last error that occurred when trying * to update the exchange info. @@ -1385,6 +1403,7 @@ export const codecForExchangeListItem = (): Codec<ExchangeListItem> => .property("exchangeEntryStatus", codecForAny()) .property("exchangeUpdateStatus", codecForAny()) .property("ageRestrictionOptions", codecForList(codecForNumber())) + .property("scopeInfo", codecForScopeInfo()) .build("ExchangeListItem"); export const codecForExchangesListResponse = (): Codec<ExchangesListResponse> => @@ -1395,6 +1414,8 @@ export const codecForExchangesListResponse = (): Codec<ExchangesListResponse> => export interface AcceptManualWithdrawalResult { /** * Payto URIs that can be used to fund the withdrawal. + * + * @deprecated in favor of withdrawalAccountsList */ exchangePaytoUris: string[]; @@ -1403,15 +1424,17 @@ export interface AcceptManualWithdrawalResult { */ reservePub: string; - withdrawalAccountsList: WithdrawalAccountInfo[]; + withdrawalAccountsList: WithdrawalExchangeAccountDetails[]; transactionId: TransactionIdStr; } -export interface ManualWithdrawalDetails { +export interface WithdrawalDetailsForAmount { /** * Did the user accept the current version of the exchange's * terms of service? + * + * @deprecated the client should query the exchange entry instead */ tosAccepted: boolean; @@ -1435,20 +1458,25 @@ export interface ManualWithdrawalDetails { /** * Ways to pay the exchange. * - * @deprecated in favor of withdrawalAccountList + * @deprecated in favor of withdrawalAccountsList */ paytoUris: string[]; /** - * Ways to pay the exchange, including + * Ways to pay the exchange, including accounts that require currency conversion. */ - withdrawalAccountList: WithdrawalAccountInfo[]; + withdrawalAccountsList: WithdrawalExchangeAccountDetails[]; /** * If the exchange supports age-restricted coins it will return * the array of ages. */ ageRestrictionOptions?: number[]; + + /** + * Scope info of the currency withdrawn. + */ + scopeInfo: ScopeInfo; } /** @@ -1463,11 +1491,6 @@ export interface DenomSelectionState { }[]; } -export interface WireAccountDetails { - paytoUri: string; - creditRestrictions?: AccountRestriction[]; -} - /** * Information about what will happen doing a withdrawal. * @@ -1481,7 +1504,7 @@ export interface ExchangeWithdrawalDetails { */ exchangeWireAccounts: string[]; - withdrawalAccountList: WithdrawalAccountInfo[]; + exchangeCreditAccountDetails: WithdrawalExchangeAccountDetails[]; /** * Selected denominations for withdraw. @@ -1567,6 +1590,18 @@ export interface GetExchangeTosResult { */ contentType: string; + /** + * Language of the returned content. + * + * If missing, language is unknown. + */ + contentLanguage: string | undefined; + + /** + * Available languages as advertised by the exchange. + */ + tosAvailableLanguages: string[]; + tosStatus: ExchangeTosStatus; } @@ -1621,10 +1656,27 @@ export const codecForIntegrationTestV2Args = (): Codec<IntegrationTestV2Args> => .property("corebankApiBaseUrl", codecForString()) .build("IntegrationTestV2Args"); +export interface GetExchangeEntryByUrlRequest { + exchangeBaseUrl: string; +} + +export const codecForGetExchangeEntryByUrlRequest = + (): Codec<GetExchangeEntryByUrlRequest> => + buildCodecForObject<GetExchangeEntryByUrlRequest>() + .property("exchangeBaseUrl", codecForString()) + .build("GetExchangeEntryByUrlRequest"); + +export type GetExchangeEntryByUrlResponse = ExchangeListItem; + export interface AddExchangeRequest { exchangeBaseUrl: string; - masterPub?: string; + + /** + * @deprecated use a separate API call to start a forced exchange update instead + */ forceUpdate?: boolean; + + masterPub?: string; } export const codecForAddExchangeRequest = (): Codec<AddExchangeRequest> => @@ -1657,12 +1709,14 @@ export const codecForForceExchangeUpdateRequest = export interface GetExchangeTosRequest { exchangeBaseUrl: string; acceptedFormat?: string[]; + acceptLanguage?: string; } export const codecForGetExchangeTosRequest = (): Codec<GetExchangeTosRequest> => buildCodecForObject<GetExchangeTosRequest>() .property("exchangeBaseUrl", codecForString()) .property("acceptedFormat", codecOptional(codecForList(codecForString()))) + .property("acceptLanguage", codecOptional(codecForString())) .build("GetExchangeTosRequest"); export interface AcceptManualWithdrawalRequest { @@ -2451,6 +2505,17 @@ export const codecForCheckPeerPushDebitRequest = export interface CheckPeerPushDebitResponse { amountRaw: AmountString; amountEffective: AmountString; + exchangeBaseUrl: string; + /** + * Maximum expiration date, based on how close the coins + * used for the payment are to expiry. + * + * The value is based on when the wallet would typically + * automatically refresh the coins on its own, leaving enough + * time to get a refund for the push payment and refresh the + * coin. + */ + maxExpirationDate: TalerProtocolTimestamp; } export interface InitiatePeerPushDebitRequest { @@ -2482,15 +2547,22 @@ export interface PreparePeerPullDebitRequest { export interface PreparePeerPushCreditResponse { contractTerms: PeerContractTerms; - /** - * @deprecated - */ - amount: AmountString; amountRaw: AmountString; amountEffective: AmountString; - peerPushCreditId: string; transactionId: string; + + exchangeBaseUrl: string; + + /** + * @deprecated use transaction ID instead. + */ + peerPushCreditId: string; + + /** + * @deprecated + */ + amount: AmountString; } export interface PreparePeerPullDebitResponse { @@ -2769,7 +2841,85 @@ export interface TestingWaitTransactionRequest { txState: TransactionState; } -export interface WithdrawalAccountInfo { +export interface WithdrawalExchangeAccountDetails { + /** + * Payto URI to credit the exchange. + * + * Depending on whether the (manual!) withdrawal is accepted or just + * being checked, this already includes the subject with the + * reserve public key. + */ paytoUri: string; - transferAmount: AmountString; + + /** + * Status that indicates whether the account can be used + * by the user to send funds for a withdrawal. + * + * ok: account should be shown to the user + * error: account should not be shown to the user, UIs might render the error (in conversionError), + * especially in dev mode. + */ + status: "ok" | "error"; + + /** + * Transfer amount. Might be in a different currency than the requested + * amount for withdrawal. + * + * Redundant with the amount in paytoUri, just included to avoid parsing. + * + * Only included if this account does a currency conversion. + */ + transferAmount?: AmountString; + + /** + * Currency specification for the external currency. + * + * Only included if this account requires a currency conversion. + */ + currencySpecification?: CurrencySpecification; + + /** + * Further restrictions for sending money to the + * exchange. + */ + creditRestrictions?: AccountRestriction[]; + + /** + * Error that happened when attempting to request the conversion rate. + */ + conversionError?: TalerErrorDetail; +} + +export interface PrepareWithdrawExchangeRequest { + /** + * A taler://withdraw-exchange URI. + */ + talerUri: string; +} + +export const codecForPrepareWithdrawExchangeRequest = + (): Codec<PrepareWithdrawExchangeRequest> => + buildCodecForObject<PrepareWithdrawExchangeRequest>() + .property("talerUri", codecForString()) + .build("PrepareWithdrawExchangeRequest"); + +export interface PrepareWithdrawExchangeResponse { + /** + * Base URL of the exchange that already existed + * or was ephemerally added as an exchange entry to + * the wallet. + */ + exchangeBaseUrl: string; + + /** + * Amount from the taler://withdraw-exchange URI. + * Only present if specified in the URI. + */ + amount?: AmountString; +} + +export interface ExchangeEntryState { + tosStatus: ExchangeTosStatus; + exchangeEntryStatus: ExchangeEntryStatus; + exchangeUpdateStatus: ExchangeUpdateStatus; } diff --git a/packages/taler-wallet-cli/Makefile b/packages/taler-wallet-cli/Makefile @@ -45,3 +45,7 @@ install: $(MAKE) deps $(MAKE) install-nodeps endif + +.PHONY: deb +deb: + dpkg-buildpackage -rfakeroot -b -uc -us diff --git a/packages/taler-wallet-cli/debian/changelog b/packages/taler-wallet-cli/debian/changelog @@ -1,3 +1,15 @@ +taler-wallet-cli (0.9.3-1) unstable; urgency=low + + * Misc bugfixes. + + -- Christian Grothoff <grothoff@gnu.org> Tue, 13 Dec 2023 18:53:15 -0700 + +taler-wallet-cli (0.9.3) unstable; urgency=low + + * First release for GNU Taler v0.9.3. + + -- Christian Grothoff <grothoff@gnu.org> Wed, 29 Nov 2023 08:53:15 -0800 + taler-wallet-cli (0.9.2-2) unstable; urgency=low * Release with various Debian package fixes. diff --git a/packages/taler-wallet-cli/debian/rules b/packages/taler-wallet-cli/debian/rules @@ -1,32 +1,15 @@ #!/usr/bin/make -f -include /usr/share/dpkg/default.mk -TALER_WALLET_HOME = /usr/share/taler-wallet-cli +%: + dh ${@} -build: build-arch build-indep -build-arch: - true -build-indep: - true -override_dh_auto_install: - dh_install bin/taler-wallet-cli.mjs $(TALER_WALLET_HOME)/node_modules/taler-wallet-cli/bin - dh_install dist/taler-wallet-cli-bundled.cjs $(TALER_WALLET_HOME)/node_modules/taler-wallet-cli/dist - dh_install dist/taler-wallet-cli-bundled.cjs.map $(TALER_WALLET_HOME)/node_modules/taler-wallet-cli/dist - dh_link $(TALER_WALLET_HOME)/node_modules/taler-wallet-cli/bin/taler-wallet-cli.mjs /usr/bin/taler-wallet-cli +# Override because our configure doesn't like extra arguments. +override_dh_auto_configure: + ./configure --prefix=/usr override_dh_builddeb: dh_builddeb -- -Zgzip -binary: - dh $@ -binary-arch: - dh $@ -binary-indep: - dh $@ - -clean: - true - # Override this step because it's very slow and likely # unnecessary for us. override_dh_strip_nondeterminism: diff --git a/packages/taler-wallet-cli/package.json b/packages/taler-wallet-cli/package.json @@ -32,13 +32,13 @@ ], "devDependencies": { "@types/node": "^18.11.17", - "prettier": "^2.8.8", - "typedoc": "^0.25.1", - "typescript": "^5.2.2" + "prettier": "^3.1.1", + "typedoc": "^0.25.4", + "typescript": "^5.3.3" }, "dependencies": { "@gnu-taler/taler-util": "workspace:*", "@gnu-taler/taler-wallet-core": "workspace:*", - "tslib": "^2.5.3" + "tslib": "^2.6.2" } } \ No newline at end of file diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts @@ -156,8 +156,9 @@ function applyVerbose(verbose: boolean): void { } declare const __VERSION__: string; +declare const __GIT_HASH__: string; function printVersion(): void { - console.log(__VERSION__); + console.log(`${__VERSION__} ${__GIT_HASH__}`); processExit(0); } @@ -799,9 +800,8 @@ exchangesCli .flag("force", ["-f", "--force"]) .action(async (args) => { await withWallet(args, async (wallet) => { - await wallet.client.call(WalletApiOperation.AddExchange, { + await wallet.client.call(WalletApiOperation.UpdateExchangeEntry, { exchangeBaseUrl: args.exchangesUpdateCmd.url, - forceUpdate: args.exchangesUpdateCmd.force, }); }); }); diff --git a/packages/taler-wallet-core/package.json b/packages/taler-wallet-core/package.json @@ -50,38 +50,35 @@ } }, "devDependencies": { - "@ava/typescript": "^4.0.0", + "@ava/typescript": "^4.1.0", "@gnu-taler/pogen": "workspace:*", "@typescript-eslint/eslint-plugin": "^5.36.1", "@typescript-eslint/parser": "^5.36.1", - "ava": "^4.3.3", - "c8": "^7.11.0", + "ava": "^6.0.1", + "c8": "^8.0.1", "eslint": "^8.8.0", - "eslint-config-airbnb-typescript": "^16.1.0", - "eslint-plugin-import": "^2.25.4", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.28.0", + "eslint-config-airbnb-typescript": "^17.1.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.8.0", + "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.3.0", "jed": "^1.1.1", "po2json": "^0.4.5", - "prettier": "^2.8.8", - "typedoc": "^0.25.1", - "typescript": "^5.2.2" + "prettier": "^3.1.1", + "typedoc": "^0.25.4", + "typescript": "^5.3.3" }, "dependencies": { "@gnu-taler/idb-bridge": "workspace:*", "@gnu-taler/taler-util": "workspace:*", "@types/node": "^18.11.17", - "big-integer": "^1.6.51", - "fflate": "^0.7.4", - "tslib": "^2.5.3" + "big-integer": "^1.6.52", + "fflate": "^0.8.1", + "tslib": "^2.6.2" }, "ava": { - "ignoredByWatcher": [ - "src/**/*" - ], "files": [ "lib/**/*test.*" ] } -} -\ No newline at end of file +} diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts @@ -103,6 +103,8 @@ import { EncryptContractForDepositResponse, EncryptContractRequest, EncryptContractResponse, + SignCoinHistoryRequest, + SignCoinHistoryResponse, SignDeletePurseRequest, SignDeletePurseResponse, SignPurseMergeRequest, @@ -243,6 +245,10 @@ export interface TalerCryptoInterface { signDeletePurse( req: SignDeletePurseRequest, ): Promise<SignDeletePurseResponse>; + + signCoinHistoryRequest( + req: SignCoinHistoryRequest, + ): Promise<SignCoinHistoryResponse>; } /** @@ -427,6 +433,11 @@ export const nullCrypto: TalerCryptoInterface = { ): Promise<SignDeletePurseResponse> { throw new Error("Function not implemented."); }, + signCoinHistoryRequest: function ( + req: SignCoinHistoryRequest, + ): Promise<SignCoinHistoryResponse> { + throw new Error("Function not implemented."); + }, }; export type WithArg<X> = X extends (req: infer T) => infer R @@ -1705,6 +1716,23 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { sig: sigResp.sig, }; }, + async signCoinHistoryRequest( + tci: TalerCryptoInterfaceR, + req: SignCoinHistoryRequest, + ): Promise<SignCoinHistoryResponse> { + const coinHistorySigBlob = buildSigPS( + TalerSignaturePurpose.WALLET_COIN_HISTORY, + ) + .put(bufferForUint64(req.startOffset)) + .build(); + const sigResp = await tci.eddsaSign(tci, { + msg: encodeCrock(coinHistorySigBlob), + priv: req.coinPriv, + }); + return { + sig: sigResp.sig, + }; + }, }; export interface EddsaSignRequest { diff --git a/packages/taler-wallet-core/src/crypto/cryptoTypes.ts b/packages/taler-wallet-core/src/crypto/cryptoTypes.ts @@ -279,6 +279,16 @@ export interface SignDeletePurseResponse { sig: EddsaSignatureString; } +export interface SignCoinHistoryRequest { + coinPub: string; + coinPriv: string; + startOffset: number; +} + +export interface SignCoinHistoryResponse { + sig: EddsaSignatureString; +} + export interface SignReservePurseCreateRequest { mergeTimestamp: TalerProtocolTimestamp; diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts @@ -26,6 +26,7 @@ import { IDBRequest, IDBTransaction, structuredEncapsulate, + structuredRevive, } from "@gnu-taler/idb-bridge"; import { AbsoluteTime, @@ -56,7 +57,7 @@ import { TransactionIdStr, UnblindedSignature, WireInfo, - WithdrawalAccountInfo, + WithdrawalExchangeAccountDetails, codecForAny, } from "@gnu-taler/taler-util"; import { DbRetryInfo, TaskIdentifiers } from "./operations/common.js"; @@ -568,21 +569,6 @@ export interface ExchangeDetailsRecord { */ globalFees: ExchangeGlobalFees[]; - /** - * Etag of the current ToS of the exchange. - */ - tosCurrentEtag: string; - - /** - * Information about ToS acceptance from the user. - */ - tosAccepted: - | { - etag: string; - timestamp: DbPreciseTimestamp; - } - | undefined; - wireInfo: WireInfo; /** @@ -614,8 +600,8 @@ export enum ExchangeEntryDbUpdateStatus { Initial = 1, InitialUpdate = 2, Suspended = 3, - Failed = 4, - OutdatedUpdate = 5, + UnavailableUpdate = 4, + // Reserved 5 for backwards compatibility. Ready = 6, ReadyUpdate = 7, } @@ -659,6 +645,15 @@ export interface ExchangeEntryRecord { updateStatus: ExchangeEntryDbUpdateStatus; /** + * Etag of the current ToS of the exchange. + */ + tosCurrentEtag: string | undefined; + + tosAcceptedEtag: string | undefined; + + tosAcceptedTimestamp: DbPreciseTimestamp | undefined; + + /** * Last time when the exchange /keys info was updated. */ lastUpdate: DbPreciseTimestamp | undefined; @@ -1378,6 +1373,10 @@ export interface WgInfoBankIntegrated { * a Taler-integrated bank. */ bankInfo: ReserveBankInfo; + /** + * Info about withdrawal accounts, possibly including currency conversion. + */ + exchangeCreditAccounts?: WithdrawalExchangeAccountDetails[]; } export interface WgInfoBankManual { @@ -1386,7 +1385,7 @@ export interface WgInfoBankManual { /** * Info about withdrawal accounts, possibly including currency conversion. */ - exchangeCreditAccounts?: WithdrawalAccountInfo[]; + exchangeCreditAccounts?: WithdrawalExchangeAccountDetails[]; } export interface WgInfoBankPeerPull { @@ -1800,12 +1799,20 @@ export enum PeerPushDebitStatus { PendingCreatePurse = 0x0100_0000 /* ACTIVE_START */, PendingReady = 0x0100_0001, AbortingDeletePurse = 0x0103_0000, - AbortingRefresh = 0x0103_0001, + /** + * Refresh after the purse got deleted by the wallet. + */ + AbortingRefreshDeleted = 0x0103_0001, + /** + * Refresh after the purse expired. + */ + AbortingRefreshExpired = 0x0103_0002, SuspendedCreatePurse = 0x0110_0000, SuspendedReady = 0x0110_0001, SuspendedAbortingDeletePurse = 0x0113_0000, - SuspendedAbortingRefresh = 0x0113_0001, + SuspendedAbortingRefreshDeleted = 0x0113_0001, + SuspendedAbortingRefreshExpired = 0x0113_0002, Done = 0x0500_0000, Aborted = 0x0503_0000, @@ -1900,6 +1907,7 @@ export enum PeerPullPaymentCreditStatus { Done = 0x0500_0000, Failed = 0x0501_0000, + Expired = 0x0502_0000, Aborted = 0x0503_0000, } @@ -2835,7 +2843,7 @@ function checkDbDump(x: any): x is DbDump { } export async function importDb(db: IDBDatabase, dumpJson: any): Promise<void> { - const d = dumpJson; + const d = structuredRevive(dumpJson); if (checkDbDump(d)) { const walletDb = d.databases[TALER_WALLET_MAIN_DB_NAME]; if (!walletDb) { diff --git a/packages/taler-wallet-core/src/dbless.ts b/packages/taler-wallet-core/src/dbless.ts @@ -59,8 +59,11 @@ import { } from "@gnu-taler/taler-util/http"; import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js"; import { DenominationRecord } from "./db.js"; -import { isWithdrawableDenom } from "./index.js"; -import { ExchangeInfo } from "./operations/exchanges.js"; +import { + ExchangeInfo, + ExchangeKeysDownloadResult, + isWithdrawableDenom, +} from "./index.js"; import { assembleRefreshRevealRequest } from "./operations/refresh.js"; import { getBankStatusUrl, @@ -379,14 +382,19 @@ export async function refreshCoin(req: { // benchmark the exchange. } -export async function createFakebankReserve(args: { +/** + * Create a reserve for testing withdrawals. + * + * The reserve is created using the test-only API "/admin/add-incoming". + */ +export async function createTestingReserve(args: { http: HttpRequestLibrary; - fakebankBaseUrl: string; + corebankApiBaseUrl: string; amount: string; reservePub: string; exchangeInfo: ExchangeInfo; }): Promise<void> { - const { http, fakebankBaseUrl, amount, reservePub } = args; + const { http, corebankApiBaseUrl, amount, reservePub } = args; const paytoUri = args.exchangeInfo.keys.accounts[0].payto_uri; const pt = parsePaytoUri(paytoUri); if (!pt) { @@ -394,13 +402,19 @@ export async function createFakebankReserve(args: { } const components = pt.targetPath.split("/"); const creditorAcct = components[components.length - 1]; - const fbReq = await http.postJson( - new URL(`${creditorAcct}/admin/add-incoming`, fakebankBaseUrl).href, + const fbReq = await http.fetch( + new URL( + `accounts/${creditorAcct}/taler-wire-gateway/admin/add-incoming`, + corebankApiBaseUrl, + ).href, { - amount, - reserve_pub: reservePub, - debit_account: "payto://x-taler-bank/localhost/testdebtor", + method: "POST", + body: { + amount, + reserve_pub: reservePub, + debit_account: "payto://x-taler-bank/localhost/testdebtor", + }, }, ); - const fbResp = await readSuccessResponseJsonOrThrow(fbReq, codecForAny()); + await readSuccessResponseJsonOrThrow(fbReq, codecForAny()); } diff --git a/packages/taler-wallet-core/src/host-impl.node.ts b/packages/taler-wallet-core/src/host-impl.node.ts @@ -147,7 +147,7 @@ export async function createNativeWalletHost2( args.persistentStoragePath && args.persistentStoragePath.endsWith(".json") ) { - logger.info("using legacy file-based DB backend"); + logger.info("using JSON file DB backend (slow, only use for testing)"); dbResp = await makeFileDb(args); } else { logger.info("using sqlite3 DB backend"); diff --git a/packages/taler-wallet-core/src/host-impl.qtart.ts b/packages/taler-wallet-core/src/host-impl.qtart.ts @@ -30,20 +30,19 @@ import type { } from "@gnu-taler/idb-bridge"; // eslint-disable-next-line no-duplicate-imports import { + AccessStats, BridgeIDBFactory, MemoryBackend, createSqliteBackend, shimIndexedDB, } from "@gnu-taler/idb-bridge"; -import { AccessStats } from "@gnu-taler/idb-bridge"; -import { SynchronousCryptoWorkerFactoryPlain } from "./crypto/workers/synchronousWorkerFactoryPlain.js"; -import { openTalerDatabase } from "./index.js"; -import { Logger, enableNativeLogging } from "@gnu-taler/taler-util"; +import { Logger } from "@gnu-taler/taler-util"; import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; -import { SetTimeoutTimerAPI } from "./util/timer.js"; -import { Wallet } from "./wallet.js"; import { qjsOs, qjsStd } from "@gnu-taler/taler-util/qtart"; +import { SynchronousCryptoWorkerFactoryPlain } from "./crypto/workers/synchronousWorkerFactoryPlain.js"; import { DefaultNodeWalletArgs, makeTempfileId } from "./host-common.js"; +import { SetTimeoutTimerAPI } from "./util/timer.js"; +import { Wallet } from "./wallet.js"; const logger = new Logger("host-impl.qtart.ts"); @@ -171,10 +170,10 @@ export async function createNativeWalletHost2( args.persistentStoragePath && args.persistentStoragePath.endsWith(".json") ) { - logger.info("using JSON file DB backend (slow!)"); + logger.info("using JSON file DB backend (slow, only use for testing)"); dbResp = await makeFileDb(args); } else { - logger.info("using sqlite3 DB backend (experimental!)"); + logger.info("using sqlite3 DB backend"); dbResp = await makeSqliteDb(args); } diff --git a/packages/taler-wallet-core/src/internal-wallet-state.ts b/packages/taler-wallet-core/src/internal-wallet-state.ts @@ -55,6 +55,7 @@ import { import { TimerGroup } from "./util/timer.js"; import { WalletConfig } from "./wallet-api-types.js"; import { IDBFactory } from "@gnu-taler/idb-bridge"; +import { ReadyExchangeSummary } from "./index.js"; export const EXCHANGE_COINS_LOCK = "exchange-coins-lock"; export const EXCHANGE_RESERVES_LOCK = "exchange-reserves-lock"; @@ -107,17 +108,14 @@ export interface ExchangeOperations { }>, exchangeBaseUrl: string, ): Promise<ExchangeDetailsRecord | undefined>; - updateExchangeFromUrl( + fetchFreshExchange( ws: InternalWalletState, baseUrl: string, options?: { forceNow?: boolean; cancellationToken?: CancellationToken; }, - ): Promise<{ - exchange: ExchangeEntryRecord; - exchangeDetails: ExchangeDetailsRecord; - }>; + ): Promise<ReadyExchangeSummary>; } export interface RecoupOperations { diff --git a/packages/taler-wallet-core/src/operations/balance.ts b/packages/taler-wallet-core/src/operations/balance.ts @@ -174,20 +174,19 @@ export async function getBalancesInsideTransaction( return; case WithdrawalGroupStatus.PendingReady: case WithdrawalGroupStatus.AbortingBank: - case WithdrawalGroupStatus.PendingAml: - b.flagIncomingAml = true; - break; - case WithdrawalGroupStatus.PendingKyc: - b.flagIncomingKyc = true; - break; case WithdrawalGroupStatus.PendingQueryingStatus: case WithdrawalGroupStatus.SuspendedWaitConfirmBank: case WithdrawalGroupStatus.SuspendedReady: case WithdrawalGroupStatus.SuspendedRegisteringBank: + case WithdrawalGroupStatus.SuspendedAbortingBank: + case WithdrawalGroupStatus.SuspendedQueryingStatus: + // Pending, but no special flag. + break; case WithdrawalGroupStatus.SuspendedKyc: + case WithdrawalGroupStatus.PendingKyc: b.flagIncomingKyc = true; break; - case WithdrawalGroupStatus.SuspendedAbortingBank: + case WithdrawalGroupStatus.PendingAml: case WithdrawalGroupStatus.SuspendedAml: b.flagIncomingAml = true; break; @@ -195,8 +194,6 @@ export async function getBalancesInsideTransaction( case WithdrawalGroupStatus.PendingWaitConfirmBank: b.flagIncomingConfirmation = true; break; - case WithdrawalGroupStatus.SuspendedQueryingStatus: - break; default: assertUnreachable(wgRecord.status); } @@ -236,8 +233,12 @@ export async function getBalancesInsideTransaction( if (v.flagIncomingConfirmation) { flags.push(BalanceFlag.IncomingConfirmation); } + if (v.flagOutgoingKyc) { + flags.push(BalanceFlag.OutgoingKyc); + } balancesResponse.balances.push({ scopeInfo: { + // FIXME: obtain REAL scopeInfo instead of faking a global currency type: ScopeType.Global, currency: Amounts.currencyOf(v.available), }, diff --git a/packages/taler-wallet-core/src/operations/common.ts b/packages/taler-wallet-core/src/operations/common.ts @@ -26,6 +26,7 @@ import { CoinRefreshRequest, CoinStatus, Duration, + ExchangeEntryState, ExchangeEntryStatus, ExchangeListItem, ExchangeTosStatus, @@ -37,6 +38,8 @@ import { NotificationType, OperationErrorInfo, RefreshReason, + ScopeInfo, + ScopeType, TalerError, TalerErrorCode, TalerErrorDetail, @@ -73,7 +76,10 @@ import { PendingTaskType, TaskId } from "../pending-types.js"; import { assertUnreachable } from "../util/assertUnreachable.js"; import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js"; import { GetReadOnlyAccess, GetReadWriteAccess } from "../util/query.js"; -import { constructTransactionIdentifier } from "./transactions.js"; +import { + constructTransactionIdentifier, + parseTransactionIdentifier, +} from "./transactions.js"; const logger = new Logger("operations/common.ts"); @@ -318,11 +324,7 @@ function convertTaskToTransactionId( } } -/** - * For tasks that process a transaction, - * generate a state transition notification. - */ -async function taskToTransactionNotification( +async function makeTransactionRetryNotification( ws: InternalWalletState, tx: GetReadOnlyAccess<typeof WalletStoresV1>, pendingTaskId: string, @@ -351,6 +353,75 @@ async function taskToTransactionNotification( return notif; } +async function makeExchangeRetryNotification( + ws: InternalWalletState, + tx: GetReadOnlyAccess<typeof WalletStoresV1>, + pendingTaskId: string, + e: TalerErrorDetail | undefined, +): Promise<WalletNotification | undefined> { + logger.info("making exchange retry notification"); + const parsedTaskId = parseTaskIdentifier(pendingTaskId); + if (parsedTaskId.tag !== PendingTaskType.ExchangeUpdate) { + throw Error("invalid task identifier"); + } + const rec = await tx.exchanges.get(parsedTaskId.exchangeBaseUrl); + + if (!rec) { + logger.info(`exchange ${parsedTaskId.exchangeBaseUrl} not found`); + return undefined; + } + + const notif: WalletNotification = { + type: NotificationType.ExchangeStateTransition, + exchangeBaseUrl: parsedTaskId.exchangeBaseUrl, + oldExchangeState: getExchangeState(rec), + newExchangeState: getExchangeState(rec), + }; + if (e) { + notif.errorInfo = { + code: e.code as number, + hint: e.hint, + }; + } + return notif; +} + +/** + * Generate an appropriate error transition notification + * for applicable tasks. + * + * Namely, transition notifications are generated for: + * - exchange update errors + * - transactions + */ +async function taskToRetryNotification( + ws: InternalWalletState, + tx: GetReadOnlyAccess<typeof WalletStoresV1>, + pendingTaskId: string, + e: TalerErrorDetail | undefined, +): Promise<WalletNotification | undefined> { + const parsedTaskId = parseTaskIdentifier(pendingTaskId); + + switch (parsedTaskId.tag) { + case PendingTaskType.ExchangeUpdate: + return makeExchangeRetryNotification(ws, tx, pendingTaskId, e); + case PendingTaskType.PeerPullCredit: + case PendingTaskType.PeerPullDebit: + case PendingTaskType.Withdraw: + case PendingTaskType.PeerPushCredit: + case PendingTaskType.Deposit: + case PendingTaskType.Refresh: + case PendingTaskType.RewardPickup: + case PendingTaskType.PeerPushDebit: + case PendingTaskType.Purchase: + return makeTransactionRetryNotification(ws, tx, pendingTaskId, e); + case PendingTaskType.Backup: + case PendingTaskType.ExchangeCheckRefresh: + case PendingTaskType.Recoup: + return undefined; + } +} + async function storePendingTaskError( ws: InternalWalletState, pendingTaskId: string, @@ -370,7 +441,7 @@ async function storePendingTaskError( retryRecord.retryInfo = DbRetryInfo.increment(retryRecord.retryInfo); } await tx.operationRetries.put(retryRecord); - return taskToTransactionNotification(ws, tx, pendingTaskId, e); + return taskToRetryNotification(ws, tx, pendingTaskId, e); }); if (maybeNotification) { ws.notify(maybeNotification); @@ -389,7 +460,7 @@ export async function resetPendingTaskTimeout( retryRecord.retryInfo = DbRetryInfo.reset(); await tx.operationRetries.put(retryRecord); } - return taskToTransactionNotification(ws, tx, pendingTaskId, undefined); + return taskToRetryNotification(ws, tx, pendingTaskId, undefined); }); if (maybeNotification) { ws.notify(maybeNotification); @@ -417,7 +488,7 @@ async function storePendingTaskPending( } await tx.operationRetries.put(retryRecord); if (hadError) { - return taskToTransactionNotification(ws, tx, pendingTaskId, undefined); + return taskToRetryNotification(ws, tx, pendingTaskId, undefined); } else { return undefined; } @@ -530,80 +601,95 @@ export enum TombstoneTag { DeletePeerPushCredit = "delete-peer-push-credit", } -export function getExchangeTosStatus( - exchangeDetails: ExchangeDetailsRecord, +export function getExchangeTosStatusFromRecord( + exchange: ExchangeEntryRecord, ): ExchangeTosStatus { - if (!exchangeDetails.tosAccepted) { + if (!exchange.tosAcceptedEtag) { return ExchangeTosStatus.Proposed; } - if (exchangeDetails.tosAccepted?.etag == exchangeDetails.tosCurrentEtag) { + if (exchange.tosAcceptedEtag == exchange.tosCurrentEtag) { return ExchangeTosStatus.Accepted; } return ExchangeTosStatus.Proposed; } -export function makeExchangeListItem( +export function getExchangeUpdateStatusFromRecord( r: ExchangeEntryRecord, - exchangeDetails: ExchangeDetailsRecord | undefined, - lastError: TalerErrorDetail | undefined, -): ExchangeListItem { - const lastUpdateErrorInfo: OperationErrorInfo | undefined = lastError - ? { - error: lastError, - } - : undefined; - - let exchangeUpdateStatus: ExchangeUpdateStatus; +): ExchangeUpdateStatus { switch (r.updateStatus) { - case ExchangeEntryDbUpdateStatus.Failed: - exchangeUpdateStatus = ExchangeUpdateStatus.Failed; - break; + case ExchangeEntryDbUpdateStatus.UnavailableUpdate: + return ExchangeUpdateStatus.UnavailableUpdate; case ExchangeEntryDbUpdateStatus.Initial: - exchangeUpdateStatus = ExchangeUpdateStatus.Initial; - break; + return ExchangeUpdateStatus.Initial; case ExchangeEntryDbUpdateStatus.InitialUpdate: - exchangeUpdateStatus = ExchangeUpdateStatus.InitialUpdate; - break; - case ExchangeEntryDbUpdateStatus.OutdatedUpdate: - exchangeUpdateStatus = ExchangeUpdateStatus.OutdatedUpdate; - break; + return ExchangeUpdateStatus.InitialUpdate; case ExchangeEntryDbUpdateStatus.Ready: - exchangeUpdateStatus = ExchangeUpdateStatus.Ready; - break; + return ExchangeUpdateStatus.Ready; case ExchangeEntryDbUpdateStatus.ReadyUpdate: - exchangeUpdateStatus = ExchangeUpdateStatus.ReadyUpdate; - break; + return ExchangeUpdateStatus.ReadyUpdate; case ExchangeEntryDbUpdateStatus.Suspended: - exchangeUpdateStatus = ExchangeUpdateStatus.Suspended; - break; + return ExchangeUpdateStatus.Suspended; } +} - let exchangeEntryStatus: ExchangeEntryStatus; +export function getExchangeEntryStatusFromRecord( + r: ExchangeEntryRecord, +): ExchangeEntryStatus { switch (r.entryStatus) { case ExchangeEntryDbRecordStatus.Ephemeral: - exchangeEntryStatus = ExchangeEntryStatus.Ephemeral; - break; + return ExchangeEntryStatus.Ephemeral; case ExchangeEntryDbRecordStatus.Preset: - exchangeEntryStatus = ExchangeEntryStatus.Preset; - break; + return ExchangeEntryStatus.Preset; case ExchangeEntryDbRecordStatus.Used: - exchangeEntryStatus = ExchangeEntryStatus.Used; - break; + return ExchangeEntryStatus.Used; + } +} + +/** + * Compute the state of an exchange entry from the DB + * record. + */ +export function getExchangeState(r: ExchangeEntryRecord): ExchangeEntryState { + return { + exchangeEntryStatus: getExchangeEntryStatusFromRecord(r), + exchangeUpdateStatus: getExchangeUpdateStatusFromRecord(r), + tosStatus: getExchangeTosStatusFromRecord(r), + }; +} + +export function makeExchangeListItem( + r: ExchangeEntryRecord, + exchangeDetails: ExchangeDetailsRecord | undefined, + lastError: TalerErrorDetail | undefined, +): ExchangeListItem { + const lastUpdateErrorInfo: OperationErrorInfo | undefined = lastError + ? { + error: lastError, + } + : undefined; + + let scopeInfo: ScopeInfo | undefined = undefined; + if (exchangeDetails) { + // FIXME: Look up actual scope info. + scopeInfo = { + currency: exchangeDetails.currency, + type: ScopeType.Exchange, + url: r.baseUrl, + }; } return { exchangeBaseUrl: r.baseUrl, currency: exchangeDetails?.currency ?? r.presetCurrencyHint, - exchangeUpdateStatus, - exchangeEntryStatus, - tosStatus: exchangeDetails - ? getExchangeTosStatus(exchangeDetails) - : ExchangeTosStatus.Pending, + exchangeUpdateStatus: getExchangeUpdateStatusFromRecord(r), + exchangeEntryStatus: getExchangeEntryStatusFromRecord(r), + tosStatus: getExchangeTosStatusFromRecord(r), ageRestrictionOptions: exchangeDetails?.ageMask ? AgeRestriction.getAgeGroupsFromMask(exchangeDetails.ageMask) : [], paytoUris: exchangeDetails?.wireInfo.accounts.map((x) => x.payto_uri) ?? [], lastUpdateErrorInfo, + scopeInfo, }; } @@ -839,7 +925,6 @@ export type ParsedTaskIdentifier = | { tag: PendingTaskType.Backup; backupProviderBaseUrl: string } | { tag: PendingTaskType.Deposit; depositGroupId: string } | { tag: PendingTaskType.ExchangeCheckRefresh; exchangeBaseUrl: string } - | { tag: PendingTaskType.ExchangeUpdate; exchangeBaseUrl: string } | { tag: PendingTaskType.PeerPullDebit; peerPullDebitId: string } | { tag: PendingTaskType.PeerPullCredit; pursePub: string } | { tag: PendingTaskType.PeerPushCredit; peerPushCreditId: string } @@ -859,13 +944,13 @@ export function parseTaskIdentifier(x: string): ParsedTaskIdentifier { const [type, ...rest] = task; switch (type) { case PendingTaskType.Backup: - return { tag: type, backupProviderBaseUrl: rest[0] }; + return { tag: type, backupProviderBaseUrl: decodeURIComponent(rest[0]) }; case PendingTaskType.Deposit: return { tag: type, depositGroupId: rest[0] }; case PendingTaskType.ExchangeCheckRefresh: - return { tag: type, exchangeBaseUrl: rest[0] }; + return { tag: type, exchangeBaseUrl: decodeURIComponent(rest[0]) }; case PendingTaskType.ExchangeUpdate: - return { tag: type, exchangeBaseUrl: rest[0] }; + return { tag: type, exchangeBaseUrl: decodeURIComponent(rest[0]) }; case PendingTaskType.PeerPullCredit: return { tag: type, pursePub: rest[0] }; case PendingTaskType.PeerPullDebit: @@ -927,13 +1012,19 @@ export namespace TaskIdentifiers { return `${PendingTaskType.Withdraw}:${wg.withdrawalGroupId}` as TaskId; } export function forExchangeUpdate(exch: ExchangeEntryRecord): TaskId { - return `${PendingTaskType.ExchangeUpdate}:${exch.baseUrl}` as TaskId; + return `${PendingTaskType.ExchangeUpdate}:${encodeURIComponent( + exch.baseUrl, + )}` as TaskId; } export function forExchangeUpdateFromUrl(exchBaseUrl: string): TaskId { - return `${PendingTaskType.ExchangeUpdate}:${exchBaseUrl}` as TaskId; + return `${PendingTaskType.ExchangeUpdate}:${encodeURIComponent( + exchBaseUrl, + )}` as TaskId; } export function forExchangeCheckRefresh(exch: ExchangeEntryRecord): TaskId { - return `${PendingTaskType.ExchangeCheckRefresh}:${exch.baseUrl}` as TaskId; + return `${PendingTaskType.ExchangeCheckRefresh}:${encodeURIComponent( + exch.baseUrl, + )}` as TaskId; } export function forTipPickup(tipRecord: RewardRecord): TaskId { return `${PendingTaskType.RewardPickup}:${tipRecord.walletRewardId}` as TaskId; @@ -951,7 +1042,9 @@ export namespace TaskIdentifiers { return `${PendingTaskType.Deposit}:${depositRecord.depositGroupId}` as TaskId; } export function forBackup(backupRecord: BackupProviderRecord): TaskId { - return `${PendingTaskType.Backup}:${backupRecord.baseUrl}` as TaskId; + return `${PendingTaskType.Backup}:${encodeURIComponent( + backupRecord.baseUrl, + )}` as TaskId; } export function forPeerPushPaymentInitiation( ppi: PeerPushDebitRecord, diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts @@ -72,6 +72,7 @@ import { PendingTaskType, RefreshOperationStatus, createRefreshGroup, + getCandidateWithdrawalDenomsTx, getTotalRefreshCost, timestampPreciseToDb, timestampProtocolFromDb, @@ -1449,6 +1450,7 @@ export async function createDepositGroup( ws.notify({ type: NotificationType.BalanceChange, + hintTransactionId: transactionId, }); return { @@ -1530,6 +1532,7 @@ async function getTotalFeesForDepositAmount( const coinFee: AmountJson[] = []; const refreshFee: AmountJson[] = []; const exchangeSet: Set<string> = new Set(); + const currency = Amounts.currencyOf(total); await ws.db .mktx((x) => [x.coins, x.denominations, x.exchanges, x.exchangeDetails]) @@ -1551,11 +1554,12 @@ async function getTotalFeesForDepositAmount( coinFee.push(Amounts.parseOrThrow(denom.feeDeposit)); exchangeSet.add(coin.exchangeBaseUrl); - const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl - .iter(coin.exchangeBaseUrl) - .filter((x) => - Amounts.isSameCurrency(x.value, pcs.coinContributions[i]), - ); + const allDenoms = await getCandidateWithdrawalDenomsTx( + ws, + tx, + coin.exchangeBaseUrl, + currency, + ); const amountLeft = Amounts.sub( denom.value, pcs.coinContributions[i], diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts @@ -15,31 +15,37 @@ */ /** + * @fileoverview + * Implementation of exchange entry management in wallet-core. + * The details of exchange entry management are specified in DD48. + */ + +/** * Imports. */ import { AbsoluteTime, Amounts, CancellationToken, - canonicalizeBaseUrl, - codecForExchangeKeysJson, - DenominationPubKey, DenomKeyType, + DenomOperationMap, + DenominationInfo, + DenominationPubKey, Duration, - durationFromSpec, - encodeCrock, ExchangeAuditor, + ExchangeDetailedResponse, ExchangeGlobalFees, + ExchangeListItem, ExchangeSignKeyJson, + ExchangeTosStatus, ExchangeWireAccount, + ExchangesListResponse, + FeeDescription, + GetExchangeTosResult, GlobalFees, - hashDenomPub, - j2s, LibtoolVersion, Logger, - makeErrorDetail, NotificationType, - parsePaytoUri, Recoup, TalerError, TalerErrorCode, @@ -48,14 +54,23 @@ import { TalerProtocolDuration, TalerProtocolTimestamp, URL, + WalletNotification, WireFee, WireFeeMap, WireFeesJson, WireInfo, + canonicalizeBaseUrl, + codecForExchangeKeysJson, + durationFromSpec, + encodeCrock, + hashDenomPub, + j2s, + makeErrorDetail, + parsePaytoUri, } from "@gnu-taler/taler-util"; import { - getExpiry, HttpRequestLibrary, + getExpiry, readSuccessResponseJsonOrThrow, readSuccessResponseTextOrThrow, } from "@gnu-taler/taler-util/http"; @@ -69,66 +84,99 @@ import { import { ExchangeEntryDbRecordStatus, ExchangeEntryDbUpdateStatus, + OpenedPromise, + PendingTaskType, + WalletDbReadWriteTransaction, + createTimeline, isWithdrawableDenom, + openPromise, + selectBestForOverlappingDenominations, + selectMinimumFee, + timestampOptionalAbsoluteFromDb, + timestampOptionalPreciseFromDb, timestampPreciseFromDb, timestampPreciseToDb, timestampProtocolToDb, - WalletDbReadWriteTransaction, } from "../index.js"; -import { InternalWalletState } from "../internal-wallet-state.js"; +import { CancelFn, InternalWalletState } from "../internal-wallet-state.js"; import { checkDbInvariant } from "../util/invariants.js"; -import { - DbAccess, - GetReadOnlyAccess, - GetReadWriteAccess, -} from "../util/query.js"; +import { GetReadOnlyAccess, GetReadWriteAccess } from "../util/query.js"; import { WALLET_EXCHANGE_PROTOCOL_VERSION } from "../versions.js"; import { - runTaskWithErrorReporting, TaskIdentifiers, TaskRunResult, TaskRunResultType, + constructTaskIdentifier, + getExchangeState, + getExchangeTosStatusFromRecord, + makeExchangeListItem, + runTaskWithErrorReporting, } from "./common.js"; const logger = new Logger("exchanges.ts"); -export function getExchangeRequestTimeout(): Duration { +function getExchangeRequestTimeout(): Duration { return Duration.fromSpec({ seconds: 5, }); } -export interface ExchangeTosDownloadResult { +interface ExchangeTosDownloadResult { tosText: string; tosEtag: string; tosContentType: string; + tosContentLanguage: string | undefined; + tosAvailableLanguages: string[]; } -export async function downloadExchangeWithTermsOfService( +async function downloadExchangeWithTermsOfService( exchangeBaseUrl: string, http: HttpRequestLibrary, timeout: Duration, - contentType: string, + acceptFormat: string, + acceptLanguage: string | undefined, ): Promise<ExchangeTosDownloadResult> { - logger.trace(`downloading exchange tos (type ${contentType})`); + logger.trace(`downloading exchange tos (type ${acceptFormat})`); const reqUrl = new URL("terms", exchangeBaseUrl); - const headers = { - Accept: contentType, + const headers: { + Accept: string; + "Accept-Language"?: string; + } = { + Accept: acceptFormat, }; + if (acceptLanguage) { + headers["Accept-Language"] = acceptLanguage; + } + const resp = await http.fetch(reqUrl.href, { headers, timeout, }); const tosText = await readSuccessResponseTextOrThrow(resp); const tosEtag = resp.headers.get("etag") || "unknown"; + const tosContentLanguage = resp.headers.get("content-language") || undefined; const tosContentType = resp.headers.get("content-type") || "text/plain"; + const availLangStr = resp.headers.get("avail-languages") || ""; + // Work around exchange bug that reports the same language multiple times. + const availLangSet = new Set<string>( + availLangStr.split(",").map((x) => x.trim()), + ); + const tosAvailableLanguages = [...availLangSet]; - return { tosText, tosEtag, tosContentType }; + return { + tosText, + tosEtag, + tosContentType, + tosContentLanguage, + tosAvailableLanguages, + }; } /** * Get exchange details from the database. + * + * FIXME: Should we encapsulate the result better, instead of returning the raw DB records here? */ export async function getExchangeDetails( tx: GetReadOnlyAccess<{ @@ -153,9 +201,6 @@ export async function getExchangeDetails( ]); } -getExchangeDetails.makeContext = (db: DbAccess<typeof WalletStoresV1>) => - db.mktx((x) => [x.exchanges, x.exchangeDetails]); - /** * Mark a ToS version as accepted by the user. * @@ -169,13 +214,13 @@ export async function acceptExchangeTermsOfService( await ws.db .mktx((x) => [x.exchanges, x.exchangeDetails]) .runReadWrite(async (tx) => { - const d = await getExchangeDetails(tx, exchangeBaseUrl); - if (d) { - d.tosAccepted = { - etag: etag || d.tosCurrentEtag, - timestamp: timestampPreciseToDb(TalerPreciseTimestamp.now()), - }; - await tx.exchangeDetails.put(d); + const exch = await tx.exchanges.get(exchangeBaseUrl); + if (exch && exch.tosCurrentEtag) { + exch.tosAcceptedEtag = exch.tosCurrentEtag; + exch.tosAcceptedTimestamp = timestampPreciseToDb( + TalerPreciseTimestamp.now(), + ); + await tx.exchanges.put(exch); } }); } @@ -284,29 +329,18 @@ async function validateGlobalFees( return egf; } -export interface ExchangeInfo { - keys: ExchangeKeysDownloadResult; -} - -export async function downloadExchangeInfo( - exchangeBaseUrl: string, - http: HttpRequestLibrary, -): Promise<ExchangeInfo> { - const keysInfo = await downloadExchangeKeysInfo( - exchangeBaseUrl, - http, - Duration.getForever(), - ); - return { - keys: keysInfo, - }; -} - +/** + * Add an exchange entry to the wallet database in the + * entry state "preset". + * + * Returns the notification to the caller that should be emitted + * if the DB transaction succeeds. + */ export async function addPresetExchangeEntry( tx: WalletDbReadWriteTransaction<"exchanges">, exchangeBaseUrl: string, currencyHint?: string, -): Promise<void> { +): Promise<{ notification?: WalletNotification }> { let exchange = await tx.exchanges.get(exchangeBaseUrl); if (!exchange) { const r: ExchangeEntryRecord = { @@ -323,9 +357,22 @@ export async function addPresetExchangeEntry( nextUpdateStamp: timestampPreciseToDb( AbsoluteTime.toPreciseTimestamp(AbsoluteTime.never()), ), + tosAcceptedEtag: undefined, + tosAcceptedTimestamp: undefined, + tosCurrentEtag: undefined, }; await tx.exchanges.put(r); + return { + notification: { + type: NotificationType.ExchangeStateTransition, + exchangeBaseUrl: exchangeBaseUrl, + // Exchange did not exist yet + oldExchangeState: undefined, + newExchangeState: getExchangeState(r), + }, + }; } + return {}; } async function provideExchangeRecordInTx( @@ -339,7 +386,9 @@ async function provideExchangeRecordInTx( ): Promise<{ exchange: ExchangeEntryRecord; exchangeDetails: ExchangeDetailsRecord | undefined; + notification?: WalletNotification; }> { + let notification: WalletNotification | undefined = undefined; let exchange = await tx.exchanges.get(baseUrl); if (!exchange) { const r: ExchangeEntryRecord = { @@ -355,15 +404,24 @@ async function provideExchangeRecordInTx( AbsoluteTime.toPreciseTimestamp(AbsoluteTime.never()), ), lastKeysEtag: undefined, + tosAcceptedEtag: undefined, + tosAcceptedTimestamp: undefined, + tosCurrentEtag: undefined, }; await tx.exchanges.put(r); exchange = r; + notification = { + type: NotificationType.ExchangeStateTransition, + exchangeBaseUrl: r.baseUrl, + oldExchangeState: undefined, + newExchangeState: getExchangeState(r), + }; } const exchangeDetails = await getExchangeDetails(tx, baseUrl); - return { exchange, exchangeDetails }; + return { exchange, exchangeDetails, notification }; } -interface ExchangeKeysDownloadResult { +export interface ExchangeKeysDownloadResult { baseUrl: string; masterPublicKey: string; currency: string; @@ -393,28 +451,36 @@ async function downloadExchangeKeysInfo( const resp = await http.fetch(keysUrl.href, { timeout, }); - const exchangeKeysJsonUnchecked = await readSuccessResponseJsonOrThrow( - resp, - codecForExchangeKeysJson(), - ); - if (exchangeKeysJsonUnchecked.denominations.length === 0) { - throw TalerError.fromDetail( - TalerErrorCode.WALLET_EXCHANGE_DENOMINATIONS_INSUFFICIENT, - { - exchangeBaseUrl: baseUrl, - }, - "exchange doesn't offer any denominations", - ); - } + // We must make sure to parse out the protocol version + // before we validate the body. + // Otherwise the parser might complain with a hard to understand + // message about some other field, when it is just a version + // incompatibility. + + const keysJson = await resp.json(); - const protocolVersion = exchangeKeysJsonUnchecked.version; + const protocolVersion = keysJson.version; + if (typeof protocolVersion !== "string") { + throw Error("bad exchange, does not even specify protocol version"); + } const versionRes = LibtoolVersion.compare( WALLET_EXCHANGE_PROTOCOL_VERSION, protocolVersion, ); - if (versionRes?.compatible != true) { + if (!versionRes) { + throw TalerError.fromDetail( + TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, + { + requestUrl: resp.requestUrl, + httpStatusCode: resp.status, + requestMethod: resp.requestMethod, + }, + "exchange protocol version malformed", + ); + } + if (!versionRes.compatible) { throw TalerError.fromDetail( TalerErrorCode.WALLET_EXCHANGE_PROTOCOL_VERSION_INCOMPATIBLE, { @@ -425,6 +491,21 @@ async function downloadExchangeKeysInfo( ); } + const exchangeKeysJsonUnchecked = await readSuccessResponseJsonOrThrow( + resp, + codecForExchangeKeysJson(), + ); + + if (exchangeKeysJsonUnchecked.denominations.length === 0) { + throw TalerError.fromDetail( + TalerErrorCode.WALLET_EXCHANGE_DENOMINATIONS_INSUFFICIENT, + { + exchangeBaseUrl: baseUrl, + }, + "exchange doesn't offer any denominations", + ); + } + const currency = exchangeKeysJsonUnchecked.currency; const currentDenominations: DenominationRecord[] = []; @@ -512,14 +593,15 @@ async function downloadExchangeKeysInfo( }; } -export async function downloadTosFromAcceptedFormat( +async function downloadTosFromAcceptedFormat( ws: InternalWalletState, baseUrl: string, timeout: Duration, acceptedFormat?: string[], + acceptLanguage?: string, ): Promise<ExchangeTosDownloadResult> { let tosFound: ExchangeTosDownloadResult | undefined; - //Remove this when exchange supports multiple content-type in accept header + // Remove this when exchange supports multiple content-type in accept header if (acceptedFormat) for (const format of acceptedFormat) { const resp = await downloadExchangeWithTermsOfService( @@ -527,6 +609,7 @@ export async function downloadTosFromAcceptedFormat( ws.http, timeout, format, + acceptLanguage, ); if (resp.tosContentType === format) { tosFound = resp; @@ -542,58 +625,253 @@ export async function downloadTosFromAcceptedFormat( ws.http, timeout, "text/plain", + acceptLanguage, ); } /** - * FIXME: Split this into two parts: (a) triggering the exchange - * to be updated and (b) waiting for the update to finish. + * Transition an exchange into an updating state. + * + * If the update is forced, the exchange is put into an updating state + * even if the old information should still be up to date. + * + * If the exchange entry doesn't exist, + * a new ephemeral entry is created. */ -export async function updateExchangeFromUrl( +export async function startUpdateExchangeEntry( + ws: InternalWalletState, + exchangeBaseUrl: string, + options: { forceUpdate?: boolean } = {}, +): Promise<void> { + const canonBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl); + + const now = AbsoluteTime.now(); + + const { notification } = await ws.db + .mktx((x) => [x.exchanges, x.exchangeDetails]) + .runReadWrite(async (tx) => { + return provideExchangeRecordInTx(ws, tx, exchangeBaseUrl, now); + }); + + if (notification) { + ws.notify(notification); + } + + const { oldExchangeState, newExchangeState } = await ws.db + .mktx((x) => [x.exchanges, x.operationRetries]) + .runReadWrite(async (tx) => { + const r = await tx.exchanges.get(canonBaseUrl); + if (!r) { + throw Error("exchange not found"); + } + const oldExchangeState = getExchangeState(r); + switch (r.updateStatus) { + case ExchangeEntryDbUpdateStatus.UnavailableUpdate: + break; + case ExchangeEntryDbUpdateStatus.Suspended: + break; + case ExchangeEntryDbUpdateStatus.ReadyUpdate: + break; + case ExchangeEntryDbUpdateStatus.Ready: { + const nextUpdateTimestamp = AbsoluteTime.fromPreciseTimestamp( + timestampPreciseFromDb(r.nextUpdateStamp), + ); + // Only update if entry is outdated or update is forced. + if ( + options.forceUpdate || + AbsoluteTime.isExpired(nextUpdateTimestamp) + ) { + r.updateStatus = ExchangeEntryDbUpdateStatus.ReadyUpdate; + } + break; + } + case ExchangeEntryDbUpdateStatus.Initial: + r.updateStatus = ExchangeEntryDbUpdateStatus.InitialUpdate; + break; + } + await tx.exchanges.put(r); + const newExchangeState = getExchangeState(r); + // Reset retries for updating the exchange entry. + const taskId = TaskIdentifiers.forExchangeUpdate(r); + await tx.operationRetries.delete(taskId); + return { oldExchangeState, newExchangeState }; + }); + ws.notify({ + type: NotificationType.ExchangeStateTransition, + exchangeBaseUrl: canonBaseUrl, + newExchangeState: newExchangeState, + oldExchangeState: oldExchangeState, + }); + ws.workAvailable.trigger(); +} + +export interface NotificationWaiter { + waitNext(): Promise<void>; + cancel(): void; +} + +export function createNotificationWaiter( + ws: InternalWalletState, + pred: (x: WalletNotification) => boolean, +): NotificationWaiter { + ws.ensureTaskLoopRunning(); + let cancelFn: CancelFn | undefined = undefined; + let p: OpenedPromise<void> | undefined = undefined; + + return { + cancel() { + cancelFn?.(); + }, + waitNext(): Promise<void> { + if (!p) { + p = openPromise(); + cancelFn = ws.addNotificationListener((notif) => { + if (pred(notif)) { + // We got a notification that matches our predicate. + // Resolve promise for existing waiters, + // and create a new promise to wait for the next + // notification occurrence. + const myResolve = p?.resolve; + const myCancel = cancelFn; + p = undefined; + cancelFn = undefined; + myResolve?.(); + myCancel?.(); + } + }); + } + return p.promise; + }, + }; +} + +/** + * Basic information about an exchange in a ready state. + */ +export interface ReadyExchangeSummary { + exchangeBaseUrl: string; + currency: string; + masterPub: string; + tosStatus: ExchangeTosStatus; + tosAcceptedEtag: string | undefined; + tosCurrentEtag: string | undefined; + wireInfo: WireInfo; + protocolVersionRange: string; + tosAcceptedTimestamp: TalerPreciseTimestamp | undefined; +} + +/** + * Ensure that a fresh exchange entry exists for the given + * exchange base URL. + * + * The cancellation token can be used to abort waiting for the + * updated exchange entry. + * + * If an exchange entry for the database doesn't exist in the + * DB, it will be added ephemerally. + * + * If the expectedMasterPub is given and does not match the actual + * master pub, an exception will be thrown. However, the exchange + * will still have been added as an ephemeral exchange entry. + */ +export async function fetchFreshExchange( ws: InternalWalletState, baseUrl: string, options: { - checkMasterPub?: string; - forceNow?: boolean; cancellationToken?: CancellationToken; + forceUpdate?: boolean; + expectedMasterPub?: string; } = {}, -): Promise<{ - exchange: ExchangeEntryRecord; - exchangeDetails: ExchangeDetailsRecord; -}> { +): Promise<ReadyExchangeSummary> { const canonUrl = canonicalizeBaseUrl(baseUrl); - const res = await runTaskWithErrorReporting( - ws, - TaskIdentifiers.forExchangeUpdateFromUrl(canonUrl), - () => updateExchangeFromUrlHandler(ws, canonUrl, options), - ); - switch (res.type) { - case TaskRunResultType.Finished: { - const now = AbsoluteTime.now(); - const { exchange, exchangeDetails } = await ws.db - .mktx((x) => [x.exchanges, x.exchangeDetails]) - .runReadWrite(async (tx) => { - let exchange = await tx.exchanges.get(canonUrl); - const exchangeDetails = await getExchangeDetails(tx, canonUrl); - return { exchange, exchangeDetails }; - }); - if (!exchange) { - throw Error("exchange not found"); - } - if (!exchangeDetails) { - throw Error("exchange details not found"); - } - return { exchange, exchangeDetails }; + const operationId = constructTaskIdentifier({ + tag: PendingTaskType.ExchangeUpdate, + exchangeBaseUrl: canonUrl, + }); + + const oldExchange = await ws.db + .mktx((x) => [x.exchanges]) + .runReadOnly(async (tx) => { + return tx.exchanges.get(canonUrl); + }); + + let needsUpdate = false; + + if (!oldExchange || options.forceUpdate) { + needsUpdate = true; + await startUpdateExchangeEntry(ws, canonUrl, { + forceUpdate: options.forceUpdate, + }); + } else { + const nextUpdate = timestampOptionalAbsoluteFromDb( + oldExchange.nextUpdateStamp, + ); + if ( + nextUpdate == null || + AbsoluteTime.isExpired(nextUpdate) || + oldExchange.updateStatus !== ExchangeEntryDbUpdateStatus.Ready + ) { + needsUpdate = true; } - case TaskRunResultType.Error: - throw TalerError.fromUncheckedDetail(res.errorDetail); + } + + if (needsUpdate) { + await runTaskWithErrorReporting(ws, operationId, () => + updateExchangeFromUrlHandler(ws, canonUrl), + ); + } + + const { exchange, exchangeDetails } = await ws.db + .mktx((x) => [x.exchanges, x.exchangeDetails]) + .runReadOnly(async (tx) => { + const exchange = await tx.exchanges.get(canonUrl); + const exchangeDetails = await getExchangeDetails(tx, canonUrl); + return { exchange, exchangeDetails }; + }); + + if (!exchange) { + throw Error("exchange entry does not exist anymore"); + } + + switch (exchange.updateStatus) { + case ExchangeEntryDbUpdateStatus.Ready: + case ExchangeEntryDbUpdateStatus.ReadyUpdate: + break; default: - throw Error(`unexpected operation result (${res.type})`); + throw Error("unable to update exchange"); + } + + if (!exchangeDetails) { + throw Error("invariant failed"); } + + const res: ReadyExchangeSummary = { + currency: exchangeDetails.currency, + exchangeBaseUrl: canonUrl, + masterPub: exchangeDetails.masterPublicKey, + tosStatus: getExchangeTosStatusFromRecord(exchange), + tosAcceptedEtag: exchange.tosAcceptedEtag, + wireInfo: exchangeDetails.wireInfo, + protocolVersionRange: exchangeDetails.protocolVersionRange, + tosCurrentEtag: exchange.tosCurrentEtag, + tosAcceptedTimestamp: timestampOptionalPreciseFromDb( + exchange.tosAcceptedTimestamp, + ), + }; + + if (options.expectedMasterPub) { + if (res.masterPub !== options.expectedMasterPub) { + throw Error( + "public key of the exchange does not match expected public key", + ); + } + } + return res; } /** - * Update or add exchange DB entry by fetching the /keys and /wire information. + * Update an exchange entry in the wallet's database + * by fetching the /keys and /wire information. * Optionally link the reserve entry to the new or existing * exchange entry in then DB. */ @@ -601,48 +879,11 @@ export async function updateExchangeFromUrlHandler( ws: InternalWalletState, exchangeBaseUrl: string, options: { - checkMasterPub?: string; - forceNow?: boolean; cancellationToken?: CancellationToken; } = {}, ): Promise<TaskRunResult> { - const forceNow = options.forceNow ?? false; - logger.trace( - `updating exchange info for ${exchangeBaseUrl}, forced: ${forceNow}`, - ); - - const now = AbsoluteTime.now(); + logger.trace(`updating exchange info for ${exchangeBaseUrl}`); exchangeBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl); - let isNewExchange = true; - const { exchange, exchangeDetails } = await ws.db - .mktx((x) => [x.exchanges, x.exchangeDetails]) - .runReadWrite(async (tx) => { - let oldExch = await tx.exchanges.get(exchangeBaseUrl); - if (oldExch) { - isNewExchange = false; - } - return provideExchangeRecordInTx(ws, tx, exchangeBaseUrl, now); - }); - - if ( - !forceNow && - exchangeDetails !== undefined && - !AbsoluteTime.isExpired( - AbsoluteTime.fromPreciseTimestamp( - timestampPreciseFromDb(exchange.nextUpdateStamp), - ), - ) - ) { - logger.trace("using existing exchange info"); - - if (options.checkMasterPub) { - if (exchangeDetails.masterPublicKey !== options.checkMasterPub) { - throw Error(`master public key mismatch`); - } - } - - return TaskRunResult.finished(); - } logger.trace("updating exchange /keys info"); @@ -654,12 +895,6 @@ export async function updateExchangeFromUrlHandler( timeout, ); - if (options.checkMasterPub) { - if (keysInfo.masterPublicKey !== options.checkMasterPub) { - throw Error(`master public key mismatch`); - } - } - logger.trace("validating exchange wire info"); const version = LibtoolVersion.parseVersion(keysInfo.protocolVersion); @@ -740,6 +975,7 @@ export async function updateExchangeFromUrlHandler( logger.warn(`exchange ${exchangeBaseUrl} no longer present`); return; } + const oldExchangeState = getExchangeState(r); const existingDetails = await getExchangeDetails(tx, r.baseUrl); if (!existingDetails) { detailsPointerChanged = true; @@ -753,7 +989,6 @@ export async function updateExchangeFromUrlHandler( } // FIXME: We need to do some consistency checks! } - const existingTosAccepted = existingDetails?.tosAccepted; const newDetails: ExchangeDetailsRecord = { auditors: keysInfo.auditors, currency: keysInfo.currency, @@ -763,10 +998,9 @@ export async function updateExchangeFromUrlHandler( globalFees, exchangeBaseUrl: r.baseUrl, wireInfo, - tosCurrentEtag: tosDownload.tosEtag, - tosAccepted: existingTosAccepted, ageMask, }; + r.tosCurrentEtag = tosDownload.tosEtag; if (existingDetails?.rowId) { newDetails.rowId = existingDetails.rowId; } @@ -787,6 +1021,7 @@ export async function updateExchangeFromUrlHandler( updateClock: timestampPreciseToDb(TalerPreciseTimestamp.now()), }; } + r.updateStatus = ExchangeEntryDbUpdateStatus.Ready; await tx.exchanges.put(r); const drRowId = await tx.exchangeDetails.put(newDetails); checkDbInvariant(typeof drRowId.key === "number"); @@ -881,14 +1116,18 @@ export async function updateExchangeFromUrlHandler( recoupGroupId = await ws.recoupOps.createRecoupGroup( ws, tx, - exchange.baseUrl, + exchangeBaseUrl, newlyRevokedCoinPubs, ); } + const newExchangeState = getExchangeState(r); + return { exchange: r, exchangeDetails: newDetails, + oldExchangeState, + newExchangeState, }; }); @@ -904,11 +1143,12 @@ export async function updateExchangeFromUrlHandler( logger.trace("done updating exchange info in database"); - if (isNewExchange) { - ws.notify({ - type: NotificationType.ExchangeAdded, - }); - } + ws.notify({ + type: NotificationType.ExchangeStateTransition, + exchangeBaseUrl, + newExchangeState: updated.newExchangeState, + oldExchangeState: updated.oldExchangeState, + }); return TaskRunResult.finished(); } @@ -926,8 +1166,8 @@ export async function getExchangePaytoUri( ): Promise<string> { // We do the update here, since the exchange might not even exist // yet in our database. - const details = await getExchangeDetails - .makeContext(ws.db) + const details = await ws.db + .mktx((x) => [x.exchangeDetails, x.exchanges]) .runReadOnly(async (tx) => { return getExchangeDetails(tx, exchangeBaseUrl); }); @@ -947,3 +1187,247 @@ export async function getExchangePaytoUri( )}`, ); } + +/** + * Get the exchange ToS in the requested format. + * Try to download in the accepted format not cached. + */ +export async function getExchangeTos( + ws: InternalWalletState, + exchangeBaseUrl: string, + acceptedFormat?: string[], + acceptLanguage?: string, +): Promise<GetExchangeTosResult> { + // FIXME: download ToS in acceptable format if passed! + const exch = await fetchFreshExchange(ws, exchangeBaseUrl); + + const tosDownload = await downloadTosFromAcceptedFormat( + ws, + exchangeBaseUrl, + getExchangeRequestTimeout(), + acceptedFormat, + acceptLanguage, + ); + + await ws.db + .mktx((x) => [x.exchanges, x.exchangeDetails]) + .runReadWrite(async (tx) => { + const updateExchangeEntry = await tx.exchanges.get(exchangeBaseUrl); + if (updateExchangeEntry) { + updateExchangeEntry.tosCurrentEtag = tosDownload.tosEtag; + await tx.exchanges.put(updateExchangeEntry); + } + }); + + return { + acceptedEtag: exch.tosAcceptedEtag, + currentEtag: tosDownload.tosEtag, + content: tosDownload.tosText, + contentType: tosDownload.tosContentType, + contentLanguage: tosDownload.tosContentLanguage, + tosStatus: exch.tosStatus, + tosAvailableLanguages: tosDownload.tosAvailableLanguages, + }; +} + +export interface ExchangeInfo { + keys: ExchangeKeysDownloadResult; +} + +/** + * Helper function to download the exchange /keys info. + * + * Only used for testing / dbless wallet. + */ +export async function downloadExchangeInfo( + exchangeBaseUrl: string, + http: HttpRequestLibrary, +): Promise<ExchangeInfo> { + const keysInfo = await downloadExchangeKeysInfo( + exchangeBaseUrl, + http, + Duration.getForever(), + ); + return { + keys: keysInfo, + }; +} + +export async function getExchanges( + ws: InternalWalletState, +): Promise<ExchangesListResponse> { + const exchanges: ExchangeListItem[] = []; + await ws.db + .mktx((x) => [ + x.exchanges, + x.exchangeDetails, + x.denominations, + x.operationRetries, + ]) + .runReadOnly(async (tx) => { + const exchangeRecords = await tx.exchanges.iter().toArray(); + for (const r of exchangeRecords) { + const exchangeDetails = await getExchangeDetails(tx, r.baseUrl); + const opRetryRecord = await tx.operationRetries.get( + TaskIdentifiers.forExchangeUpdate(r), + ); + exchanges.push( + makeExchangeListItem(r, exchangeDetails, opRetryRecord?.lastError), + ); + } + }); + return { exchanges }; +} + +export async function getExchangeDetailedInfo( + ws: InternalWalletState, + exchangeBaseurl: string, +): Promise<ExchangeDetailedResponse> { + //TODO: should we use the forceUpdate parameter? + const exchange = await ws.db + .mktx((x) => [x.exchanges, x.exchangeDetails, x.denominations]) + .runReadOnly(async (tx) => { + const ex = await tx.exchanges.get(exchangeBaseurl); + const dp = ex?.detailsPointer; + if (!dp) { + return; + } + const { currency } = dp; + const exchangeDetails = await getExchangeDetails(tx, ex.baseUrl); + if (!exchangeDetails) { + return; + } + const denominationRecords = + await tx.denominations.indexes.byExchangeBaseUrl.getAll(ex.baseUrl); + + if (!denominationRecords) { + return; + } + + const denominations: DenominationInfo[] = denominationRecords.map((x) => + DenominationRecord.toDenomInfo(x), + ); + + return { + info: { + exchangeBaseUrl: ex.baseUrl, + currency, + paytoUris: exchangeDetails.wireInfo.accounts.map((x) => x.payto_uri), + auditors: exchangeDetails.auditors, + wireInfo: exchangeDetails.wireInfo, + globalFees: exchangeDetails.globalFees, + }, + denominations, + }; + }); + + if (!exchange) { + throw Error(`exchange with base url "${exchangeBaseurl}" not found`); + } + + const denoms = exchange.denominations.map((d) => ({ + ...d, + group: Amounts.stringifyValue(d.value), + })); + const denomFees: DenomOperationMap<FeeDescription[]> = { + deposit: createTimeline( + denoms, + "denomPubHash", + "stampStart", + "stampExpireDeposit", + "feeDeposit", + "group", + selectBestForOverlappingDenominations, + ), + refresh: createTimeline( + denoms, + "denomPubHash", + "stampStart", + "stampExpireWithdraw", + "feeRefresh", + "group", + selectBestForOverlappingDenominations, + ), + refund: createTimeline( + denoms, + "denomPubHash", + "stampStart", + "stampExpireWithdraw", + "feeRefund", + "group", + selectBestForOverlappingDenominations, + ), + withdraw: createTimeline( + denoms, + "denomPubHash", + "stampStart", + "stampExpireWithdraw", + "feeWithdraw", + "group", + selectBestForOverlappingDenominations, + ), + }; + + const transferFees = Object.entries( + exchange.info.wireInfo.feesForType, + ).reduce( + (prev, [wireType, infoForType]) => { + const feesByGroup = [ + ...infoForType.map((w) => ({ + ...w, + fee: Amounts.stringify(w.closingFee), + group: "closing", + })), + ...infoForType.map((w) => ({ ...w, fee: w.wireFee, group: "wire" })), + ]; + prev[wireType] = createTimeline( + feesByGroup, + "sig", + "startStamp", + "endStamp", + "fee", + "group", + selectMinimumFee, + ); + return prev; + }, + {} as Record<string, FeeDescription[]>, + ); + + const globalFeesByGroup = [ + ...exchange.info.globalFees.map((w) => ({ + ...w, + fee: w.accountFee, + group: "account", + })), + ...exchange.info.globalFees.map((w) => ({ + ...w, + fee: w.historyFee, + group: "history", + })), + ...exchange.info.globalFees.map((w) => ({ + ...w, + fee: w.purseFee, + group: "purse", + })), + ]; + + const globalFees = createTimeline( + globalFeesByGroup, + "signature", + "startDate", + "endDate", + "fee", + "group", + selectMinimumFee, + ); + + return { + exchange: { + ...exchange.info, + denomFees, + transferFees, + globalFees, + }, + }; +} diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts @@ -98,6 +98,7 @@ import { WalletStoresV1, } from "../db.js"; import { + getCandidateWithdrawalDenomsTx, PendingTaskType, RefundGroupRecord, RefundGroupStatus, @@ -152,6 +153,7 @@ export async function getTotalPaymentCost( ws: InternalWalletState, pcs: PayCoinSelection, ): Promise<AmountJson> { + const currency = Amounts.currencyOf(pcs.paymentAmount); return ws.db .mktx((x) => [x.coins, x.denominations]) .runReadOnly(async (tx) => { @@ -170,11 +172,12 @@ export async function getTotalPaymentCost( "can't calculate payment cost, denomination for coin not found", ); } - const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl - .iter(coin.exchangeBaseUrl) - .filter((x) => - Amounts.isSameCurrency(x.value, pcs.coinContributions[i]), - ); + const allDenoms = await getCandidateWithdrawalDenomsTx( + ws, + tx, + coin.exchangeBaseUrl, + currency, + ); const amountLeft = Amounts.sub( denom.value, pcs.coinContributions[i], @@ -529,9 +532,8 @@ async function processDownloadProposal( fulfillmentUrl.startsWith("https://")); let otherPurchase: PurchaseRecord | undefined; if (isResourceFulfillmentUrl) { - otherPurchase = await tx.purchases.indexes.byFulfillmentUrl.get( - fulfillmentUrl, - ); + otherPurchase = + await tx.purchases.indexes.byFulfillmentUrl.get(fulfillmentUrl); } // FIXME: Adjust this to account for refunds, don't count as repurchase // if original order is refunded. @@ -933,7 +935,13 @@ async function handleInsufficientFunds( }); }); - ws.notify({ type: NotificationType.BalanceChange }); + ws.notify({ + type: NotificationType.BalanceChange, + hintTransactionId: constructTransactionIdentifier({ + tag: TransactionType.Payment, + proposalId, + }), + }); } async function unblockBackup( @@ -1272,7 +1280,7 @@ export async function generateDepositPermissions( * Run the operation handler for a payment * and return the result as a {@link ConfirmPayResult}. */ -export async function runPayForConfirmPay( +async function runPayForConfirmPay( ws: InternalWalletState, proposalId: string, ): Promise<ConfirmPayResult> { @@ -1482,7 +1490,10 @@ export async function confirmPay( }); notifyTransition(ws, transactionId, transitionInfo); - ws.notify({ type: NotificationType.BalanceChange }); + ws.notify({ + type: NotificationType.BalanceChange, + hintTransactionId: transactionId, + }); return runPayForConfirmPay(ws, proposalId); } @@ -2367,6 +2378,7 @@ async function processPurchaseAutoRefund( } const oldTxState = computePayMerchantTransactionState(p); p.purchaseStatus = PurchaseStatus.Done; + p.refundAmountAwaiting = undefined; const newTxState = computePayMerchantTransactionState(p); await tx.purchases.put(p); return { oldTxState, newTxState }; @@ -2548,6 +2560,7 @@ async function processPurchaseQueryRefund( } const oldTxState = computePayMerchantTransactionState(p); p.purchaseStatus = PurchaseStatus.Done; + p.refundAmountAwaiting = undefined; const newTxState = computePayMerchantTransactionState(p); await tx.purchases.put(p); return { oldTxState, newTxState }; @@ -2634,6 +2647,9 @@ export async function startRefundQueryForUri( ]); }); if (!purchaseRecord) { + logger.error( + `no purchase for order ID "${parsedUri.orderId}" from merchant "${parsedUri.merchantBaseUrl}" when processing "${talerUri}"`, + ); throw Error("no purchase found, can't refund"); } const proposalId = purchaseRecord.proposalId; diff --git a/packages/taler-wallet-core/src/operations/pay-peer-common.ts b/packages/taler-wallet-core/src/operations/pay-peer-common.ts @@ -39,6 +39,7 @@ import { InternalWalletState } from "../internal-wallet-state.js"; import type { SelectedPeerCoin } from "../util/coinSelection.js"; import { checkDbInvariant } from "../util/invariants.js"; import { getTotalRefreshCost } from "./refresh.js"; +import { getCandidateWithdrawalDenomsTx } from "./withdraw.js"; const logger = new Logger("operations/peer-to-peer.ts"); @@ -88,6 +89,7 @@ export async function getTotalPeerPaymentCost( ws: InternalWalletState, pcs: SelectedPeerCoin[], ): Promise<AmountJson> { + const currency = Amounts.currencyOf(pcs[0].contribution); return ws.db .mktx((x) => [x.coins, x.denominations]) .runReadOnly(async (tx) => { @@ -97,22 +99,30 @@ export async function getTotalPeerPaymentCost( if (!coin) { throw Error("can't calculate payment cost, coin not found"); } - const denom = await tx.denominations.get([ + const denomInfo = await ws.getDenomInfo( + ws, + tx, coin.exchangeBaseUrl, coin.denomPubHash, - ]); - if (!denom) { + ); + if (!denomInfo) { throw Error( "can't calculate payment cost, denomination for coin not found", ); } - const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl - .iter(coin.exchangeBaseUrl) - .filter((x) => Amounts.isSameCurrency(x.value, pcs[i].contribution)); - const amountLeft = Amounts.sub(denom.value, pcs[i].contribution).amount; + const allDenoms = await getCandidateWithdrawalDenomsTx( + ws, + tx, + coin.exchangeBaseUrl, + currency, + ); + const amountLeft = Amounts.sub( + denomInfo.value, + pcs[i].contribution, + ).amount; const refreshCost = getTotalRefreshCost( allDenoms, - DenominationRecord.toDenomInfo(denom), + denomInfo, amountLeft, ws.config.testing.denomselAllowLate, ); diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts b/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts @@ -63,7 +63,7 @@ import { timestampOptionalPreciseFromDb, timestampPreciseFromDb, timestampPreciseToDb, - updateExchangeFromUrl, + fetchFreshExchange, } from "../index.js"; import { InternalWalletState } from "../internal-wallet-state.js"; import { PendingTaskType } from "../pending-types.js"; @@ -107,26 +107,47 @@ async function queryPurseForPeerPullCredit( timeout: { d_ms: 60000 }, cancellationToken, }); + const transactionId = constructTransactionIdentifier({ + tag: TransactionType.PeerPullCredit, + pursePub: pullIni.pursePub, + }); logger.info(`purse status code: HTTP ${resp.status}`); - const result = await readSuccessResponseJsonOrErrorCode( + switch (resp.status) { + case HttpStatusCode.Gone: { + // Exchange says that purse doesn't exist anymore => expired! + const transitionInfo = await ws.db + .mktx((x) => [x.peerPullCredit]) + .runReadWrite(async (tx) => { + const finPi = await tx.peerPullCredit.get(pullIni.pursePub); + if (!finPi) { + logger.warn("peerPullCredit not found anymore"); + return; + } + const oldTxState = computePeerPullCreditTransactionState(finPi); + if (finPi.status === PeerPullPaymentCreditStatus.PendingReady) { + finPi.status = PeerPullPaymentCreditStatus.Expired; + } + await tx.peerPullCredit.put(finPi); + const newTxState = computePeerPullCreditTransactionState(finPi); + return { oldTxState, newTxState }; + }); + notifyTransition(ws, transactionId, transitionInfo); + return { ready: true }; + } + case HttpStatusCode.NotFound: + return { ready: false }; + } + + const result = await readSuccessResponseJsonOrThrow( resp, codecForExchangePurseStatus(), ); - if (result.isError) { - logger.info(`got purse status error, EC=${result.talerErrorResponse.code}`); - if (resp.status === 404) { - return { ready: false }; - } else { - throwUnexpectedRequestError(resp, result.talerErrorResponse); - } - } - - logger.trace(`purse status: ${j2s(result.response)}`); + logger.trace(`purse status: ${j2s(result)}`); - const depositTimestamp = result.response.deposit_timestamp; + const depositTimestamp = result.deposit_timestamp; if (!depositTimestamp || TalerProtocolTimestamp.isNever(depositTimestamp)) { logger.info("purse not ready yet (no deposit)"); @@ -157,10 +178,6 @@ async function queryPurseForPeerPullCredit( pub: reserve.reservePub, }, }); - const transactionId = constructTransactionIdentifier({ - tag: TransactionType.PeerPullCredit, - pursePub: pullIni.pursePub, - }); const transitionInfo = await ws.db .mktx((x) => [x.peerPullCredit]) .runReadWrite(async (tx) => { @@ -257,7 +274,7 @@ async function processPeerPullCreditAbortingDeletePurse( ): Promise<TaskRunResult> { const { pursePub, pursePriv } = peerPullIni; const transactionId = constructTransactionIdentifier({ - tag: TransactionType.PeerPushDebit, + tag: TransactionType.PeerPullCredit, pursePub, }); @@ -291,6 +308,7 @@ async function processPeerPullCreditAbortingDeletePurse( } const oldTxState = computePeerPullCreditTransactionState(ppiRec); ppiRec.status = PeerPullPaymentCreditStatus.Aborted; + await tx.peerPullCredit.put(ppiRec); const newTxState = computePeerPullCreditTransactionState(ppiRec); return { oldTxState, @@ -538,6 +556,7 @@ export async function processPeerPullCredit( return handlePeerPullCreditWithdrawing(ws, pullIni); case PeerPullPaymentCreditStatus.Aborted: case PeerPullPaymentCreditStatus.Failed: + case PeerPullPaymentCreditStatus.Expired: case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: case PeerPullPaymentCreditStatus.SuspendedCreatePurse: case PeerPullPaymentCreditStatus.SuspendedMergeKycRequired: @@ -746,7 +765,7 @@ export async function initiatePeerPullPayment( const exchangeBaseUrl = maybeExchangeBaseUrl; - await updateExchangeFromUrl(ws, exchangeBaseUrl); + await fetchFreshExchange(ws, exchangeBaseUrl); const mergeReserveInfo = await getMergeReserveInfo(ws, { exchangeBaseUrl: exchangeBaseUrl, @@ -815,7 +834,10 @@ export async function initiatePeerPullPayment( }); // The pending-incoming balance has changed. - ws.notify({ type: NotificationType.BalanceChange }); + ws.notify({ + type: NotificationType.BalanceChange, + hintTransactionId: transactionId, + }); notifyTransition(ws, transactionId, transitionInfo); @@ -876,6 +898,7 @@ export async function suspendPeerPullCreditTransaction( case PeerPullPaymentCreditStatus.SuspendedWithdrawing: case PeerPullPaymentCreditStatus.Aborted: case PeerPullPaymentCreditStatus.Failed: + case PeerPullPaymentCreditStatus.Expired: case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: break; default: @@ -936,6 +959,7 @@ export async function abortPeerPullCreditTransaction( case PeerPullPaymentCreditStatus.Aborted: case PeerPullPaymentCreditStatus.AbortingDeletePurse: case PeerPullPaymentCreditStatus.Failed: + case PeerPullPaymentCreditStatus.Expired: case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: break; default: @@ -990,6 +1014,7 @@ export async function failPeerPullCreditTransaction( case PeerPullPaymentCreditStatus.SuspendedWithdrawing: case PeerPullPaymentCreditStatus.Aborted: case PeerPullPaymentCreditStatus.Failed: + case PeerPullPaymentCreditStatus.Expired: break; case PeerPullPaymentCreditStatus.AbortingDeletePurse: case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: @@ -1043,6 +1068,7 @@ export async function resumePeerPullCreditTransaction( case PeerPullPaymentCreditStatus.AbortingDeletePurse: case PeerPullPaymentCreditStatus.Done: case PeerPullPaymentCreditStatus.Failed: + case PeerPullPaymentCreditStatus.Expired: case PeerPullPaymentCreditStatus.Aborted: break; case PeerPullPaymentCreditStatus.SuspendedCreatePurse: @@ -1140,6 +1166,10 @@ export function computePeerPullCreditTransactionState( return { major: TransactionMajorState.Failed, }; + case PeerPullPaymentCreditStatus.Expired: + return { + major: TransactionMajorState.Expired, + }; case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: return { major: TransactionMajorState.Aborting, @@ -1176,6 +1206,8 @@ export function computePeerPullCreditTransactionActions( return [TransactionAction.Suspend, TransactionAction.Fail]; case PeerPullPaymentCreditStatus.Failed: return [TransactionAction.Delete]; + case PeerPullPaymentCreditStatus.Expired: + return [TransactionAction.Delete]; case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: return [TransactionAction.Resume, TransactionAction.Fail]; } diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts @@ -272,7 +272,7 @@ async function processPeerPullDebitPendingDeposit( tx, currency, coinPubs, - RefreshReason.AbortPeerPushDebit, + RefreshReason.AbortPeerPullDebit, ); pi.status = PeerPullDebitRecordStatus.AbortingRefresh; @@ -460,13 +460,16 @@ export async function confirmPeerPullDebit( return pi; }); - ws.notify({ type: NotificationType.BalanceChange }); - const transactionId = constructTransactionIdentifier({ tag: TransactionType.PeerPullDebit, peerPullDebitId, }); + ws.notify({ + type: NotificationType.BalanceChange, + hintTransactionId: transactionId, + }); + return { transactionId, }; diff --git a/packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts b/packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts @@ -69,7 +69,7 @@ import { constructTaskIdentifier, runLongpollAsync, } from "./common.js"; -import { updateExchangeFromUrl } from "./exchanges.js"; +import { fetchFreshExchange } from "./exchanges.js"; import { codecForExchangePurseStatus, getMergeReserveInfo, @@ -135,12 +135,13 @@ export async function preparePeerPushCredit( tag: TransactionType.PeerPushCredit, peerPushCreditId: existing.existingPushInc.peerPushCreditId, }), + exchangeBaseUrl: existing.existingPushInc.exchangeBaseUrl, }; } const exchangeBaseUrl = uri.exchangeBaseUrl; - await updateExchangeFromUrl(ws, exchangeBaseUrl); + await fetchFreshExchange(ws, exchangeBaseUrl); const contractPriv = uri.contractPriv; const contractPub = encodeCrock(eddsaGetPublic(decodeCrock(contractPriv))); @@ -192,10 +193,10 @@ export async function preparePeerPushCredit( undefined, ); - await ws.db + const transitionInfo = await ws.db .mktx((x) => [x.contractTerms, x.peerPushCredit]) .runReadWrite(async (tx) => { - await tx.peerPushCredit.add({ + const rec: PeerPushPaymentIncomingRecord = { peerPushCreditId, contractPriv: contractPriv, exchangeBaseUrl: exchangeBaseUrl, @@ -209,15 +210,34 @@ export async function preparePeerPushCredit( estimatedAmountEffective: Amounts.stringify( wi.withdrawalAmountEffective, ), - }); - + }; + await tx.peerPushCredit.add(rec); await tx.contractTerms.put({ h: contractTermsHash, contractTermsRaw: dec.contractTerms, }); + + const newTxState = computePeerPushCreditTransactionState(rec); + + return { + oldTxState: { + major: TransactionMajorState.None, + }, + newTxState, + } satisfies TransitionInfo; }); - ws.notify({ type: NotificationType.BalanceChange }); + const transactionId = constructTransactionIdentifier({ + tag: TransactionType.PeerPushCredit, + peerPushCreditId, + }); + + notifyTransition(ws, transactionId, transitionInfo); + + ws.notify({ + type: NotificationType.BalanceChange, + hintTransactionId: transactionId, + }); return { amount: purseStatus.balance, @@ -225,10 +245,8 @@ export async function preparePeerPushCredit( amountRaw: purseStatus.balance, contractTerms: dec.contractTerms, peerPushCreditId, - transactionId: constructTransactionIdentifier({ - tag: TransactionType.PeerPushCredit, - peerPushCreditId, - }), + transactionId, + exchangeBaseUrl, }; } @@ -479,6 +497,7 @@ async function handlePendingMerge( tx, withdrawalGroupPrep, ); + withdrawalTransition = wgRes.transitionInfo; peerInc.withdrawalGroupId = wgRes.withdrawalGroup.withdrawalGroupId; break; } diff --git a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts @@ -31,18 +31,14 @@ import { TalerPreciseTimestamp, TalerProtocolTimestamp, TalerProtocolViolationError, - TalerUriAction, TransactionAction, TransactionMajorState, TransactionMinorState, TransactionState, TransactionType, - decodeCrock, encodeCrock, getRandomBytes, - hash, j2s, - stringifyTalerUri, } from "@gnu-taler/taler-util"; import { HttpResponse, @@ -89,6 +85,9 @@ export async function checkPeerPushDebit( req: CheckPeerPushDebitRequest, ): Promise<CheckPeerPushDebitResponse> { const instructedAmount = Amounts.parseOrThrow(req.amount); + logger.trace( + `checking peer push debit for ${Amounts.stringify(instructedAmount)}`, + ); const coinSelRes = await selectPeerCoins(ws, { instructedAmount }); if (coinSelRes.type === "failure") { throw TalerError.fromDetail( @@ -98,13 +97,17 @@ export async function checkPeerPushDebit( }, ); } + logger.trace(`selected peer coins (len=${coinSelRes.result.coins.length})`); const totalAmount = await getTotalPeerPaymentCost( ws, coinSelRes.result.coins, ); + logger.trace("computed total peer payment cost"); return { + exchangeBaseUrl: coinSelRes.result.exchangeBaseUrl, amountEffective: Amounts.stringify(totalAmount), amountRaw: req.amount, + maxExpirationDate: coinSelRes.result.maxExpirationDate, }; } @@ -235,16 +238,12 @@ async function processPeerPushDebitCreateReserve( nonce: peerPushInitiation.contractEncNonce, }; - logger.info(`encrypt contract request: ${j2s(encryptContractRequest)}`); + logger.trace(`encrypt contract request: ${j2s(encryptContractRequest)}`); const econtractResp = await ws.cryptoApi.encryptContractForMerge( encryptContractRequest, ); - const econtractHash = encodeCrock( - hash(decodeCrock(econtractResp.econtract.econtract)), - ); - const createPurseUrl = new URL( `purses/${peerPushInitiation.pursePub}/create`, peerPushInitiation.exchangeBaseUrl, @@ -261,7 +260,7 @@ async function processPeerPushDebitCreateReserve( econtract: econtractResp.econtract, }; - logger.info(`request body: ${j2s(reqBody)}`); + logger.trace(`request body: ${j2s(reqBody)}`); const httpResp = await ws.http.fetch(createPurseUrl.href, { method: "POST", @@ -366,7 +365,7 @@ async function processPeerPushDebitAbortingDeletePurse( coinPubs, RefreshReason.AbortPeerPushDebit, ); - ppiRec.status = PeerPushDebitStatus.AbortingRefresh; + ppiRec.status = PeerPushDebitStatus.AbortingRefreshDeleted; ppiRec.abortRefreshGroupId = refresh.refreshGroupId; await tx.peerPushDebit.put(ppiRec); const newTxState = computePeerPushDebitTransactionState(ppiRec); @@ -416,7 +415,7 @@ async function transitionPeerPushDebitTransaction( notifyTransition(ws, transactionId, transitionInfo); } -async function processPeerPushDebitAbortingRefresh( +async function processPeerPushDebitAbortingRefreshDeleted( ws: InternalWalletState, peerPushInitiation: PeerPushDebitRecord, ): Promise<TaskRunResult> { @@ -464,6 +463,54 @@ async function processPeerPushDebitAbortingRefresh( return TaskRunResult.pending(); } +async function processPeerPushDebitAbortingRefreshExpired( + ws: InternalWalletState, + peerPushInitiation: PeerPushDebitRecord, +): Promise<TaskRunResult> { + const pursePub = peerPushInitiation.pursePub; + const abortRefreshGroupId = peerPushInitiation.abortRefreshGroupId; + checkLogicInvariant(!!abortRefreshGroupId); + const transactionId = constructTransactionIdentifier({ + tag: TransactionType.PeerPushDebit, + pursePub: peerPushInitiation.pursePub, + }); + const transitionInfo = await ws.db + .mktx((x) => [x.refreshGroups, x.peerPushDebit]) + .runReadWrite(async (tx) => { + const refreshGroup = await tx.refreshGroups.get(abortRefreshGroupId); + let newOpState: PeerPushDebitStatus | undefined; + if (!refreshGroup) { + // Maybe it got manually deleted? Means that we should + // just go into failed. + logger.warn("no aborting refresh group found for deposit group"); + newOpState = PeerPushDebitStatus.Failed; + } else { + if (refreshGroup.operationStatus === RefreshOperationStatus.Finished) { + newOpState = PeerPushDebitStatus.Expired; + } else if ( + refreshGroup.operationStatus === RefreshOperationStatus.Failed + ) { + newOpState = PeerPushDebitStatus.Failed; + } + } + if (newOpState) { + const newDg = await tx.peerPushDebit.get(pursePub); + if (!newDg) { + return; + } + const oldTxState = computePeerPushDebitTransactionState(newDg); + newDg.status = newOpState; + const newTxState = computePeerPushDebitTransactionState(newDg); + await tx.peerPushDebit.put(newDg); + return { oldTxState, newTxState }; + } + return undefined; + }); + notifyTransition(ws, transactionId, transitionInfo); + // FIXME: Shouldn't this be finished in some cases?! + return TaskRunResult.pending(); +} + /** * Process the "pending(ready)" state of a peer-push-debit transaction. */ @@ -471,12 +518,16 @@ async function processPeerPushDebitReady( ws: InternalWalletState, peerPushInitiation: PeerPushDebitRecord, ): Promise<TaskRunResult> { - logger.info("processing peer-push-debit pending(ready)"); + logger.trace("processing peer-push-debit pending(ready)"); const pursePub = peerPushInitiation.pursePub; const retryTag = constructTaskIdentifier({ tag: PendingTaskType.PeerPushDebit, pursePub, }); + const transactionId = constructTaskIdentifier({ + tag: PendingTaskType.PeerPushDebit, + pursePub, + }); runLongpollAsync(ws, retryTag, async (ct) => { const mergeUrl = new URL( `purses/${pursePub}/merge`, @@ -511,14 +562,50 @@ async function processPeerPushDebitReady( }; } } else if (resp.status === HttpStatusCode.Gone) { - await transitionPeerPushDebitTransaction( - ws, - peerPushInitiation.pursePub, - { - stFrom: PeerPushDebitStatus.PendingReady, - stTo: PeerPushDebitStatus.Expired, - }, - ); + const transitionInfo = await ws.db + .mktx((x) => [ + x.peerPushDebit, + x.refreshGroups, + x.denominations, + x.coinAvailability, + x.coins, + ]) + .runReadWrite(async (tx) => { + const ppiRec = await tx.peerPushDebit.get(pursePub); + if (!ppiRec) { + return undefined; + } + if (ppiRec.status !== PeerPushDebitStatus.PendingReady) { + return undefined; + } + const currency = Amounts.currencyOf(ppiRec.amount); + const oldTxState = computePeerPushDebitTransactionState(ppiRec); + const coinPubs: CoinRefreshRequest[] = []; + + for (let i = 0; i < ppiRec.coinSel.coinPubs.length; i++) { + coinPubs.push({ + amount: ppiRec.coinSel.contributions[i], + coinPub: ppiRec.coinSel.coinPubs[i], + }); + } + + const refresh = await createRefreshGroup( + ws, + tx, + currency, + coinPubs, + RefreshReason.AbortPeerPushDebit, + ); + ppiRec.status = PeerPushDebitStatus.AbortingRefreshExpired; + ppiRec.abortRefreshGroupId = refresh.refreshGroupId; + await tx.peerPushDebit.put(ppiRec); + const newTxState = computePeerPushDebitTransactionState(ppiRec); + return { + oldTxState, + newTxState, + }; + }); + notifyTransition(ws, transactionId, transitionInfo); return { ready: true, }; @@ -570,8 +657,10 @@ export async function processPeerPushDebit( return processPeerPushDebitReady(ws, peerPushInitiation); case PeerPushDebitStatus.AbortingDeletePurse: return processPeerPushDebitAbortingDeletePurse(ws, peerPushInitiation); - case PeerPushDebitStatus.AbortingRefresh: - return processPeerPushDebitAbortingRefresh(ws, peerPushInitiation); + case PeerPushDebitStatus.AbortingRefreshDeleted: + return processPeerPushDebitAbortingRefreshDeleted(ws, peerPushInitiation); + case PeerPushDebitStatus.AbortingRefreshExpired: + return processPeerPushDebitAbortingRefreshExpired(ws, peerPushInitiation); default: { const txState = computePeerPushDebitTransactionState(peerPushInitiation); logger.warn( @@ -624,6 +713,8 @@ export async function initiatePeerPushDebit( coinSelRes.result.coins, ); + logger.info(`computed total peer payment cost`); + const pursePub = pursePair.pub; const transactionId = constructTaskIdentifier({ @@ -694,7 +785,10 @@ export async function initiatePeerPushDebit( }; }); notifyTransition(ws, transactionId, transitionInfo); - ws.notify({ type: NotificationType.BalanceChange }); + ws.notify({ + type: NotificationType.BalanceChange, + hintTransactionId: transactionId, + }); return { contractPriv: contractKeyPair.priv, @@ -720,16 +814,20 @@ export function computePeerPushDebitTransactionActions( return [TransactionAction.Delete]; case PeerPushDebitStatus.AbortingDeletePurse: return [TransactionAction.Suspend, TransactionAction.Fail]; - case PeerPushDebitStatus.AbortingRefresh: + case PeerPushDebitStatus.AbortingRefreshDeleted: return [TransactionAction.Suspend, TransactionAction.Fail]; + case PeerPushDebitStatus.AbortingRefreshExpired: + return [TransactionAction.Suspend, TransactionAction.Fail]; + case PeerPushDebitStatus.SuspendedAbortingRefreshExpired: + return [TransactionAction.Resume, TransactionAction.Fail]; case PeerPushDebitStatus.SuspendedAbortingDeletePurse: return [TransactionAction.Resume, TransactionAction.Fail]; - case PeerPushDebitStatus.SuspendedAbortingRefresh: + case PeerPushDebitStatus.SuspendedAbortingRefreshDeleted: return [TransactionAction.Resume, TransactionAction.Fail]; case PeerPushDebitStatus.SuspendedCreatePurse: return [TransactionAction.Resume, TransactionAction.Abort]; case PeerPushDebitStatus.SuspendedReady: - return [TransactionAction.Suspend, TransactionAction.Abort]; + return [TransactionAction.Resume, TransactionAction.Abort]; case PeerPushDebitStatus.Done: return [TransactionAction.Delete]; case PeerPushDebitStatus.Expired: @@ -771,9 +869,11 @@ export async function abortPeerPushDebitTransaction( // Network request might already be in-flight! newStatus = PeerPushDebitStatus.AbortingDeletePurse; break; - case PeerPushDebitStatus.SuspendedAbortingRefresh: + case PeerPushDebitStatus.SuspendedAbortingRefreshDeleted: case PeerPushDebitStatus.SuspendedAbortingDeletePurse: - case PeerPushDebitStatus.AbortingRefresh: + case PeerPushDebitStatus.SuspendedAbortingRefreshExpired: + case PeerPushDebitStatus.AbortingRefreshDeleted: + case PeerPushDebitStatus.AbortingRefreshExpired: case PeerPushDebitStatus.Done: case PeerPushDebitStatus.AbortingDeletePurse: case PeerPushDebitStatus.Aborted: @@ -822,13 +922,15 @@ export async function failPeerPushDebitTransaction( } let newStatus: PeerPushDebitStatus | undefined = undefined; switch (pushDebitRec.status) { - case PeerPushDebitStatus.AbortingRefresh: - case PeerPushDebitStatus.SuspendedAbortingRefresh: + case PeerPushDebitStatus.AbortingRefreshDeleted: + case PeerPushDebitStatus.SuspendedAbortingRefreshDeleted: // FIXME: What to do about the refresh group? newStatus = PeerPushDebitStatus.Failed; break; case PeerPushDebitStatus.AbortingDeletePurse: case PeerPushDebitStatus.SuspendedAbortingDeletePurse: + case PeerPushDebitStatus.AbortingRefreshExpired: + case PeerPushDebitStatus.SuspendedAbortingRefreshExpired: case PeerPushDebitStatus.PendingReady: case PeerPushDebitStatus.SuspendedReady: case PeerPushDebitStatus.SuspendedCreatePurse: @@ -885,8 +987,11 @@ export async function suspendPeerPushDebitTransaction( case PeerPushDebitStatus.PendingCreatePurse: newStatus = PeerPushDebitStatus.SuspendedCreatePurse; break; - case PeerPushDebitStatus.AbortingRefresh: - newStatus = PeerPushDebitStatus.SuspendedAbortingRefresh; + case PeerPushDebitStatus.AbortingRefreshDeleted: + newStatus = PeerPushDebitStatus.SuspendedAbortingRefreshDeleted; + break; + case PeerPushDebitStatus.AbortingRefreshExpired: + newStatus = PeerPushDebitStatus.SuspendedAbortingRefreshExpired; break; case PeerPushDebitStatus.AbortingDeletePurse: newStatus = PeerPushDebitStatus.SuspendedAbortingDeletePurse; @@ -895,7 +1000,8 @@ export async function suspendPeerPushDebitTransaction( newStatus = PeerPushDebitStatus.SuspendedReady; break; case PeerPushDebitStatus.SuspendedAbortingDeletePurse: - case PeerPushDebitStatus.SuspendedAbortingRefresh: + case PeerPushDebitStatus.SuspendedAbortingRefreshDeleted: + case PeerPushDebitStatus.SuspendedAbortingRefreshExpired: case PeerPushDebitStatus.SuspendedReady: case PeerPushDebitStatus.SuspendedCreatePurse: case PeerPushDebitStatus.Done: @@ -948,8 +1054,11 @@ export async function resumePeerPushDebitTransaction( case PeerPushDebitStatus.SuspendedAbortingDeletePurse: newStatus = PeerPushDebitStatus.AbortingDeletePurse; break; - case PeerPushDebitStatus.SuspendedAbortingRefresh: - newStatus = PeerPushDebitStatus.AbortingRefresh; + case PeerPushDebitStatus.SuspendedAbortingRefreshDeleted: + newStatus = PeerPushDebitStatus.AbortingRefreshDeleted; + break; + case PeerPushDebitStatus.SuspendedAbortingRefreshExpired: + newStatus = PeerPushDebitStatus.AbortingRefreshExpired; break; case PeerPushDebitStatus.SuspendedReady: newStatus = PeerPushDebitStatus.PendingReady; @@ -958,7 +1067,8 @@ export async function resumePeerPushDebitTransaction( newStatus = PeerPushDebitStatus.PendingCreatePurse; break; case PeerPushDebitStatus.PendingCreatePurse: - case PeerPushDebitStatus.AbortingRefresh: + case PeerPushDebitStatus.AbortingRefreshDeleted: + case PeerPushDebitStatus.AbortingRefreshExpired: case PeerPushDebitStatus.AbortingDeletePurse: case PeerPushDebitStatus.PendingReady: case PeerPushDebitStatus.Done: @@ -1009,17 +1119,27 @@ export function computePeerPushDebitTransactionState( major: TransactionMajorState.Aborting, minor: TransactionMinorState.DeletePurse, }; - case PeerPushDebitStatus.AbortingRefresh: + case PeerPushDebitStatus.AbortingRefreshDeleted: return { major: TransactionMajorState.Aborting, minor: TransactionMinorState.Refresh, }; + case PeerPushDebitStatus.AbortingRefreshExpired: + return { + major: TransactionMajorState.Aborting, + minor: TransactionMinorState.RefreshExpired, + }; case PeerPushDebitStatus.SuspendedAbortingDeletePurse: return { major: TransactionMajorState.SuspendedAborting, minor: TransactionMinorState.DeletePurse, }; - case PeerPushDebitStatus.SuspendedAbortingRefresh: + case PeerPushDebitStatus.SuspendedAbortingRefreshExpired: + return { + major: TransactionMajorState.SuspendedAborting, + minor: TransactionMinorState.RefreshExpired, + }; + case PeerPushDebitStatus.SuspendedAbortingRefreshDeleted: return { major: TransactionMajorState.SuspendedAborting, minor: TransactionMinorState.Refresh, diff --git a/packages/taler-wallet-core/src/operations/pending.ts b/packages/taler-wallet-core/src/operations/pending.ts @@ -22,12 +22,17 @@ * Imports. */ import { GlobalIDB } from "@gnu-taler/idb-bridge"; -import { AbsoluteTime, TransactionRecordFilter } from "@gnu-taler/taler-util"; +import { + AbsoluteTime, + TalerErrorDetail, + TalerPreciseTimestamp, + TransactionRecordFilter, +} from "@gnu-taler/taler-util"; import { BackupProviderStateTag, + DbPreciseTimestamp, DepositElementStatus, DepositGroupRecord, - DepositOperationStatus, ExchangeEntryDbUpdateStatus, PeerPullCreditRecord, PeerPullDebitRecordStatus, @@ -48,7 +53,6 @@ import { RewardRecordStatus, WalletStoresV1, WithdrawalGroupRecord, - WithdrawalGroupStatus, depositOperationNonfinalStatusRange, timestampAbsoluteFromDb, timestampOptionalAbsoluteFromDb, @@ -94,18 +98,29 @@ async function gatherExchangePending( now: AbsoluteTime, resp: PendingOperationsResponse, ): Promise<void> { - // FIXME: We should do a range query here based on the update time - // and/or the entry state. + let timestampDue: DbPreciseTimestamp | undefined = undefined; await tx.exchanges.iter().forEachAsync(async (exch) => { switch (exch.updateStatus) { case ExchangeEntryDbUpdateStatus.Initial: case ExchangeEntryDbUpdateStatus.Suspended: - case ExchangeEntryDbUpdateStatus.Failed: return; } const opUpdateExchangeTag = TaskIdentifiers.forExchangeUpdate(exch); let opr = await tx.operationRetries.get(opUpdateExchangeTag); - const timestampDue = opr?.retryInfo.nextRetry ?? exch.nextRefreshCheckStamp; + + switch (exch.updateStatus) { + case ExchangeEntryDbUpdateStatus.Ready: + timestampDue = opr?.retryInfo.nextRetry ?? exch.nextRefreshCheckStamp; + break; + case ExchangeEntryDbUpdateStatus.ReadyUpdate: + case ExchangeEntryDbUpdateStatus.InitialUpdate: + case ExchangeEntryDbUpdateStatus.UnavailableUpdate: + timestampDue = + opr?.retryInfo.nextRetry ?? + timestampPreciseToDb(TalerPreciseTimestamp.now()); + break; + } + resp.pendingOperations.push({ type: PendingTaskType.ExchangeUpdate, ...getPendingCommon( @@ -625,7 +640,7 @@ export async function iterRecordsForPeerPushInitiation( if (filter.onlyState === "nonfinal") { const keyRange = GlobalIDB.KeyRange.bound( PeerPushDebitStatus.PendingCreatePurse, - PeerPushDebitStatus.AbortingRefresh, + PeerPushDebitStatus.AbortingRefreshExpired, ); await tx.peerPushDebit.indexes.byStatus.iter(keyRange).forEachAsync(f); } else { @@ -720,11 +735,27 @@ async function gatherPeerPushCreditPending( ); } +const taskPrio: { [X in PendingTaskType]: number } = { + [PendingTaskType.Deposit]: 2, + [PendingTaskType.ExchangeUpdate]: 1, + [PendingTaskType.PeerPullCredit]: 2, + [PendingTaskType.PeerPullDebit]: 2, + [PendingTaskType.PeerPushCredit]: 2, + [PendingTaskType.Purchase]: 2, + [PendingTaskType.Recoup]: 3, + [PendingTaskType.RewardPickup]: 2, + [PendingTaskType.Refresh]: 3, + [PendingTaskType.Withdraw]: 3, + [PendingTaskType.ExchangeCheckRefresh]: 3, + [PendingTaskType.PeerPushDebit]: 2, + [PendingTaskType.Backup]: 4, +}; + export async function getPendingOperations( ws: InternalWalletState, ): Promise<PendingOperationsResponse> { const now = AbsoluteTime.now(); - return await ws.db + const resp = await ws.db .mktx((x) => [ x.backupProviders, x.exchanges, @@ -761,4 +792,12 @@ export async function getPendingOperations( await gatherPeerPushCreditPending(ws, tx, now, resp); return resp; }); + + resp.pendingOperations.sort((a, b) => { + let prioA = taskPrio[a.type]; + let prioB = taskPrio[b.type]; + return Math.sign(prioA - prioB); + }); + + return resp; } diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts @@ -50,6 +50,7 @@ import { TalerErrorCode, TalerErrorDetail, TalerPreciseTimestamp, + TalerProtocolTimestamp, TransactionAction, TransactionMajorState, TransactionState, @@ -77,6 +78,7 @@ import { WalletStoresV1, } from "../db.js"; import { + getCandidateWithdrawalDenomsTx, isWithdrawableDenom, PendingTaskType, RefreshSessionRecord, @@ -98,7 +100,7 @@ import { TaskRunResult, TaskRunResultType, } from "./common.js"; -import { updateExchangeFromUrl } from "./exchanges.js"; +import { fetchFreshExchange } from "./exchanges.js"; import { constructTransactionIdentifier, notifyTransition, @@ -221,10 +223,7 @@ async function provideRefreshSession( const { refreshGroup, coin } = d; - const { exchange } = await updateExchangeFromUrl(ws, coin.exchangeBaseUrl); - if (!exchange) { - throw Error("db inconsistent: exchange of coin not found"); - } + const exch = await fetchFreshExchange(ws, coin.exchangeBaseUrl); // FIXME: use helper functions from withdraw.ts // to update and filter withdrawable denoms. @@ -235,7 +234,7 @@ async function provideRefreshSession( const oldDenom = await ws.getDenomInfo( ws, tx, - exchange.baseUrl, + exch.exchangeBaseUrl, coin.denomPubHash, ); @@ -243,10 +242,10 @@ async function provideRefreshSession( throw Error("db inconsistent: denomination for coin not found"); } - // FIXME: use an index here, based on the withdrawal expiration time. + // FIXME: Use denom groups instead of querying all denominations! const availableDenoms: DenominationRecord[] = await tx.denominations.indexes.byExchangeBaseUrl - .iter(exchange.baseUrl) + .iter(exch.exchangeBaseUrl) .toArray(); const availableAmount = Amounts.sub( @@ -290,7 +289,10 @@ async function provideRefreshSession( const newTxState = computeRefreshTransactionState(rg); return { oldTxState, newTxState }; }); - ws.notify({ type: NotificationType.BalanceChange }); + ws.notify({ + type: NotificationType.BalanceChange, + hintTransactionId: transactionId, + }); notifyTransition(ws, transactionId, transitionInfo); return; } @@ -504,7 +506,10 @@ async function refreshMelt( newTxState, }; }); - ws.notify({ type: NotificationType.BalanceChange }); + ws.notify({ + type: NotificationType.BalanceChange, + hintTransactionId: transactionId, + }); notifyTransition(ws, transactionId, transitionInfo); return; } @@ -517,6 +522,29 @@ async function refreshMelt( derived.meltValueWithFee, )} failed in refresh group ${refreshGroupId} due to conflict`, ); + + const historySig = await ws.cryptoApi.signCoinHistoryRequest({ + coinPriv: oldCoin.coinPriv, + coinPub: oldCoin.coinPub, + startOffset: 0, + }); + + const historyUrl = new URL( + `coins/${oldCoin.coinPub}/history`, + oldCoin.exchangeBaseUrl, + ); + + const historyResp = await ws.http.fetch(historyUrl.href, { + method: "GET", + headers: { + "Taler-Coin-History-Signature": historySig.sig, + }, + }); + + const historyJson = await historyResp.json(); + logger.info(`coin history: ${j2s(historyJson)}`); + + // FIXME: Before failing and re-trying, analyse response and adjust amount } const meltResponse = await readSuccessResponseJsonOrThrow( @@ -838,7 +866,7 @@ export async function processRefreshGroup( return TaskRunResult.finished(); } // Process refresh sessions of the group in parallel. - logger.trace("processing refresh sessions for old coins"); + logger.trace("processing refresh sessions for $ old coins"); let errors: TalerErrorDetail[] = []; let inShutdown = false; const ps = refreshGroup.oldCoinPubs.map((x, i) => @@ -948,17 +976,19 @@ export async function calculateRefreshOutput( const denomsPerExchange: Record<string, DenominationRecord[]> = {}; + // FIXME: Use denom groups instead of querying all denominations! const getDenoms = async ( exchangeBaseUrl: string, ): Promise<DenominationRecord[]> => { if (denomsPerExchange[exchangeBaseUrl]) { return denomsPerExchange[exchangeBaseUrl]; } - const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl - .iter(exchangeBaseUrl) - .filter((x) => { - return isWithdrawableDenom(x, ws.config.testing.denomselAllowLate); - }); + const allDenoms = await getCandidateWithdrawalDenomsTx( + ws, + tx, + exchangeBaseUrl, + currency, + ); denomsPerExchange[exchangeBaseUrl] = allDenoms; return allDenoms; }; @@ -1137,18 +1167,30 @@ function getAutoRefreshCheckThreshold(d: DenominationRecord): AbsoluteTime { /** * Timestamp after which the wallet would do an auto-refresh. */ -function getAutoRefreshExecuteThreshold(d: DenominationRecord): AbsoluteTime { +export function getAutoRefreshExecuteThreshold(d: { + stampExpireWithdraw: TalerProtocolTimestamp; + stampExpireDeposit: TalerProtocolTimestamp; +}): AbsoluteTime { const expireWithdraw = AbsoluteTime.fromProtocolTimestamp( - timestampProtocolFromDb(d.stampExpireWithdraw), + d.stampExpireWithdraw, ); const expireDeposit = AbsoluteTime.fromProtocolTimestamp( - timestampProtocolFromDb(d.stampExpireDeposit), + d.stampExpireDeposit, ); const delta = AbsoluteTime.difference(expireWithdraw, expireDeposit); const deltaDiv = durationMul(delta, 0.5); return AbsoluteTime.addDuration(expireWithdraw, deltaDiv); } +function getAutoRefreshExecuteThresholdForDenom( + d: DenominationRecord, +): AbsoluteTime { + return getAutoRefreshExecuteThreshold({ + stampExpireWithdraw: timestampProtocolFromDb(d.stampExpireWithdraw), + stampExpireDeposit: timestampProtocolFromDb(d.stampExpireDeposit), + }); +} + export async function autoRefresh( ws: InternalWalletState, exchangeBaseUrl: string, @@ -1157,9 +1199,7 @@ export async function autoRefresh( // We must make sure that the exchange is up-to-date so that // can refresh into new denominations. - await updateExchangeFromUrl(ws, exchangeBaseUrl, { - forceNow: true, - }); + await fetchFreshExchange(ws, exchangeBaseUrl); let minCheckThreshold = AbsoluteTime.addDuration( AbsoluteTime.now(), @@ -1194,7 +1234,7 @@ export async function autoRefresh( logger.warn("denomination not in database"); continue; } - const executeThreshold = getAutoRefreshExecuteThreshold(denom); + const executeThreshold = getAutoRefreshExecuteThresholdForDenom(denom); if (AbsoluteTime.isExpired(executeThreshold)) { refreshCoins.push({ coinPub: coin.coinPub, diff --git a/packages/taler-wallet-core/src/operations/reward.ts b/packages/taler-wallet-core/src/operations/reward.ts @@ -69,7 +69,7 @@ import { TaskRunResult, TaskRunResultType, } from "./common.js"; -import { updateExchangeFromUrl } from "./exchanges.js"; +import { fetchFreshExchange } from "./exchanges.js"; import { getCandidateWithdrawalDenoms, getExchangeWithdrawalInfo, @@ -173,9 +173,10 @@ export async function prepareTip( logger.trace(`status ${j2s(tipPickupStatus)}`); const amount = Amounts.parseOrThrow(tipPickupStatus.reward_amount); + const currency = amount.currency; logger.trace("new tip, creating tip record"); - await updateExchangeFromUrl(ws, tipPickupStatus.exchange_url); + await fetchFreshExchange(ws, tipPickupStatus.exchange_url); //FIXME: is this needed? withdrawDetails is not used // * if the intention is to update the exchange information in the database @@ -192,6 +193,7 @@ export async function prepareTip( const denoms = await getCandidateWithdrawalDenoms( ws, tipPickupStatus.exchange_url, + currency, ); const selectedDenoms = selectWithdrawalDenominations(amount, denoms); @@ -429,7 +431,10 @@ export async function processTip( return { oldTxState, newTxState }; }); notifyTransition(ws, transactionId, transitionInfo); - ws.notify({ type: NotificationType.BalanceChange }); + ws.notify({ + type: NotificationType.BalanceChange, + hintTransactionId: transactionId, + }); return TaskRunResult.finished(); } diff --git a/packages/taler-wallet-core/src/operations/testing.ts b/packages/taler-wallet-core/src/operations/testing.ts @@ -58,7 +58,7 @@ import { OpenedPromise, openPromise } from "../index.js"; import { InternalWalletState } from "../internal-wallet-state.js"; import { checkLogicInvariant } from "../util/invariants.js"; import { getBalances } from "./balance.js"; -import { updateExchangeFromUrl } from "./exchanges.js"; +import { fetchFreshExchange } from "./exchanges.js"; import { confirmPay, preparePayForUri, @@ -579,9 +579,9 @@ export async function runIntegrationTest2( // waiting for notifications. logger.info("running test with arguments", args); - const exchangeInfo = await updateExchangeFromUrl(ws, args.exchangeBaseUrl); + const exchangeInfo = await fetchFreshExchange(ws, args.exchangeBaseUrl); - const currency = exchangeInfo.exchangeDetails.currency; + const currency = exchangeInfo.currency; const amountToWithdraw = Amounts.parseOrThrow(`${currency}:10`); const amountToSpend = Amounts.parseOrThrow(`${currency}:2`); @@ -684,7 +684,7 @@ export async function runIntegrationTest2( type: TalerUriAction.PayPush, exchangeBaseUrl: peerPushInit.exchangeBaseUrl, contractPriv: peerPushInit.contractPriv, - }) + }); const txDetails = await getTransactionById(ws, { transactionId: peerPushInit.transactionId, @@ -703,7 +703,7 @@ export async function runIntegrationTest2( }); await confirmPeerPushCredit(ws, { - peerPushCreditId: peerPushCredit.peerPushCreditId, + transactionId: peerPushCredit.transactionId, }); const peerPullInit = await initiatePeerPullPayment(ws, { diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts @@ -31,6 +31,7 @@ import { stringifyPayPullUri, stringifyPayPushUri, TalerErrorCode, + TalerPreciseTimestamp, Transaction, TransactionByIdRequest, TransactionIdStr, @@ -278,6 +279,7 @@ export async function getTransactionById( x.purchases, x.tombstones, x.operationRetries, + x.refundGroups, x.contractTerms, ]) .runReadWrite(async (tx) => { @@ -288,10 +290,12 @@ export async function getTransactionById( const payOpId = TaskIdentifiers.forPay(purchase); const payRetryRecord = await tx.operationRetries.get(payOpId); + const refunds = await tx.refundGroups.indexes.byProposalId.getAll(purchase.proposalId) + return buildTransactionForPurchase( purchase, contractData, - [], // FIXME: Add refunds from refund group records here. + refunds, payRetryRecord, ); }); @@ -540,7 +544,7 @@ function buildTransactionForPeerPullCredit( const silentWithdrawalErrorForInvoice = wsrOrt?.lastError && wsrOrt.lastError.code === - TalerErrorCode.WALLET_WITHDRAWAL_GROUP_INCOMPLETE && + TalerErrorCode.WALLET_WITHDRAWAL_GROUP_INCOMPLETE && Object.values(wsrOrt.lastError.errorsPerCoin ?? {}).every((e) => { return ( e.code === TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR && @@ -570,10 +574,10 @@ function buildTransactionForPeerPullCredit( kycUrl: pullCredit.kycUrl, ...(wsrOrt?.lastError ? { - error: silentWithdrawalErrorForInvoice - ? undefined - : wsrOrt.lastError, - } + error: silentWithdrawalErrorForInvoice + ? undefined + : wsrOrt.lastError, + } : {}), }; } @@ -674,6 +678,7 @@ function buildTransactionForBankIntegratedWithdraw( withdrawalDetails: { type: WithdrawalType.TalerBankIntegrationApi, confirmed: wgRecord.wgInfo.bankInfo.timestampBankConfirmed ? true : false, + exchangeCreditAccountDetails: wgRecord.wgInfo.exchangeCreditAccounts, reservePub: wgRecord.reservePub, bankConfirmationUrl: wgRecord.wgInfo.bankInfo.confirmUrl, reserveIsReady: @@ -720,7 +725,7 @@ function buildTransactionForManualWithdraw( type: WithdrawalType.ManualTransfer, reservePub: withdrawalGroup.reservePub, exchangePaytoUris, - exchangeCreditAccounts: withdrawalGroup.wgInfo.exchangeCreditAccounts, + exchangeCreditAccountDetails: withdrawalGroup.wgInfo.exchangeCreditAccounts, reserveIsReady: withdrawalGroup.status === WithdrawalGroupStatus.Done || withdrawalGroup.status === WithdrawalGroupStatus.PendingReady, @@ -923,7 +928,15 @@ async function buildTransactionForPurchase( info.fulfillmentUrl = contractData.fulfillmentUrl; } - const refunds: RefundInfoShort[] = []; + const refunds: RefundInfoShort[] = refundsInfo.map(r => ({ + amountEffective: r.amountEffective, + amountRaw: r.amountRaw, + timestamp: TalerPreciseTimestamp.round(timestampPreciseFromDb(r.timestampCreated)), + transactionId: constructTransactionIdentifier({ + tag: TransactionType.Refund, + refundGroupId: r.refundGroupId, + }) + })); const timestamp = purchaseRecord.timestampAccept; checkDbInvariant(!!timestamp); @@ -1244,11 +1257,14 @@ export async function getTransactions( const payOpId = TaskIdentifiers.forPay(purchase); const payRetryRecord = await tx.operationRetries.get(payOpId); + + const refunds = await tx.refundGroups.indexes.byProposalId.getAll(purchase.proposalId) + transactions.push( await buildTransactionForPurchase( purchase, contractData, - [], // FIXME! + refunds, payRetryRecord, ), ); diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -29,11 +29,13 @@ import { BankWithdrawDetails, CancellationToken, CoinStatus, + CurrencySpecification, DenomKeyType, DenomSelectionState, Duration, ExchangeBatchWithdrawRequest, ExchangeListItem, + ExchangeWireAccount, ExchangeWithdrawBatchResponse, ExchangeWithdrawRequest, ExchangeWithdrawResponse, @@ -43,7 +45,6 @@ import { LibtoolVersion, Logger, NotificationType, - PaytoUri, TalerError, TalerErrorCode, TalerErrorDetail, @@ -56,19 +57,19 @@ import { TransactionType, URL, UnblindedSignature, - WireAccountDetails, WithdrawUriInfoResponse, - WithdrawalAccountInfo, + WithdrawalExchangeAccountDetails, addPaytoQueryParams, canonicalizeBaseUrl, + codecForAny, codecForBankWithdrawalOperationPostResponse, codecForCashinConversionResponse, + codecForConversionBankConfig, codecForExchangeWithdrawBatchResponse, codecForIntegrationBankConfig, codecForReserveStatus, codecForWalletKycUuid, codecForWithdrawOperationStatusResponse, - createEddsaKeyPair, encodeCrock, getErrorDetailFromException, getRandomBytes, @@ -101,6 +102,7 @@ import { import { ExchangeDetailsRecord, ExchangeEntryDbRecordStatus, + Wallet, isWithdrawableDenom, timestampPreciseToDb, } from "../index.js"; @@ -134,7 +136,8 @@ import { import { getExchangeDetails, getExchangePaytoUri, - updateExchangeFromUrl, + fetchFreshExchange, + ReadyExchangeSummary, } from "./exchanges.js"; import { TransitionInfo, @@ -611,19 +614,29 @@ export async function getBankWithdrawalInfo( export async function getCandidateWithdrawalDenoms( ws: InternalWalletState, exchangeBaseUrl: string, + currency: string, ): Promise<DenominationRecord[]> { return await ws.db .mktx((x) => [x.denominations]) .runReadOnly(async (tx) => { - const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl.getAll( - exchangeBaseUrl, - ); - return allDenoms.filter((d) => - isWithdrawableDenom(d, ws.config.testing.denomselAllowLate), - ); + return getCandidateWithdrawalDenomsTx(ws, tx, exchangeBaseUrl, currency); }); } +export async function getCandidateWithdrawalDenomsTx( + ws: InternalWalletState, + tx: GetReadOnlyAccess<{ denominations: typeof WalletStoresV1.denominations }>, + exchangeBaseUrl: string, + currency: string, +): Promise<DenominationRecord[]> { + // FIXME: Use denom groups instead of querying all denominations! + const allDenoms = + await tx.denominations.indexes.byExchangeBaseUrl.getAll(exchangeBaseUrl); + return allDenoms + .filter((d) => d.currency === currency) + .filter((d) => isWithdrawableDenom(d, ws.config.testing.denomselAllowLate)); +} + /** * Generate a planchet for a coin index in a withdrawal group. * Does not actually withdraw the coin yet. @@ -869,10 +882,10 @@ async function handleKycRequired( amlStatus === AmlStatus.normal || amlStatus === undefined ? WithdrawalGroupStatus.PendingKyc : amlStatus === AmlStatus.pending - ? WithdrawalGroupStatus.PendingAml - : amlStatus === AmlStatus.fronzen - ? WithdrawalGroupStatus.SuspendedAml - : assertUnreachable(amlStatus); + ? WithdrawalGroupStatus.PendingAml + : amlStatus === AmlStatus.fronzen + ? WithdrawalGroupStatus.SuspendedAml + : assertUnreachable(amlStatus); notificationKycUrl = kycUrl; @@ -1190,7 +1203,11 @@ export async function updateWithdrawalDenoms( // First do a pass where the validity of candidate denominations // is checked and the result is stored in the database. logger.trace("getting candidate denominations"); - const denominations = await getCandidateWithdrawalDenoms(ws, exchangeBaseUrl); + const denominations = await getCandidateWithdrawalDenoms( + ws, + exchangeBaseUrl, + exchangeDetails.currency, + ); logger.trace(`got ${denominations.length} candidate denominations`); const batchSize = 500; let current = 0; @@ -1507,10 +1524,7 @@ async function processWithdrawalGroupPendingReady( withdrawalGroupId, }); - await ws.exchangeOps.updateExchangeFromUrl( - ws, - withdrawalGroup.exchangeBaseUrl, - ); + await ws.exchangeOps.fetchFreshExchange(ws, withdrawalGroup.exchangeBaseUrl); if (withdrawalGroup.denomsSel.selectedDenoms.length === 0) { logger.warn("Finishing empty withdrawal group (no denoms)"); @@ -1548,9 +1562,8 @@ async function processWithdrawalGroupPendingReady( await ws.db .mktx((x) => [x.planchets]) .runReadOnly(async (tx) => { - const planchets = await tx.planchets.indexes.byGroup.getAll( - withdrawalGroupId, - ); + const planchets = + await tx.planchets.indexes.byGroup.getAll(withdrawalGroupId); for (const p of planchets) { if (p.planchetStatus === PlanchetStatus.WithdrawalDone) { wgContext.planchetsFinished.add(p.coinPub); @@ -1641,7 +1654,10 @@ async function processWithdrawalGroupPendingReady( } notifyTransition(ws, transactionId, res.transitionInfo); - ws.notify({ type: NotificationType.BalanceChange }); + ws.notify({ + type: NotificationType.BalanceChange, + hintTransactionId: transactionId, + }); if (numPlanchetErrors > 0) { return { @@ -1755,19 +1771,18 @@ export async function getExchangeWithdrawalInfo( ageRestricted: number | undefined, ): Promise<ExchangeWithdrawalDetails> { logger.trace("updating exchange"); - const { exchange, exchangeDetails } = - await ws.exchangeOps.updateExchangeFromUrl(ws, exchangeBaseUrl); + const exchange = await ws.exchangeOps.fetchFreshExchange(ws, exchangeBaseUrl); - if (exchangeDetails.currency != instructedAmount.currency) { + if (exchange.currency != instructedAmount.currency) { // Specifiying the amount in the conversion input currency is not yet supported. // We might add support for it later. throw new Error( - `withdrawal only supported when specifying target currency ${exchangeDetails.currency}`, + `withdrawal only supported when specifying target currency ${exchange.currency}`, ); } - const withdrawalAccountList = await fetchWithdrawalAccountInfo(ws, { - exchangeDetails, + const withdrawalAccountsList = await fetchWithdrawalAccountInfo(ws, { + exchange, instructedAmount, }); @@ -1775,7 +1790,11 @@ export async function getExchangeWithdrawalInfo( await updateWithdrawalDenoms(ws, exchangeBaseUrl); logger.trace("getting candidate denoms"); - const denoms = await getCandidateWithdrawalDenoms(ws, exchangeBaseUrl); + const denoms = await getCandidateWithdrawalDenoms( + ws, + exchangeBaseUrl, + instructedAmount.currency, + ); logger.trace("selecting withdrawal denoms"); const selectedDenoms = selectWithdrawalDenominations( instructedAmount, @@ -1795,14 +1814,8 @@ export async function getExchangeWithdrawalInfo( const exchangeWireAccounts: string[] = []; - for (const account of exchangeDetails.wireInfo.accounts) { - const details: WireAccountDetails = { - paytoUri: account.payto_uri, - }; - if (account.credit_restrictions) { - details.creditRestrictions = account.credit_restrictions; - } - exchangeWireAccounts.push(details.paytoUri); + for (const account of exchange.wireInfo.accounts) { + exchangeWireAccounts.push(account.payto_uri); } let hasDenomWithAgeRestriction = false; @@ -1838,20 +1851,17 @@ export async function getExchangeWithdrawalInfo( checkLogicInvariant(!!earliestDepositExpiration); - const possibleDenoms = await ws.db - .mktx((x) => [x.denominations]) - .runReadOnly(async (tx) => { - const ds = await tx.denominations.indexes.byExchangeBaseUrl.getAll( - exchangeBaseUrl, - ); - return ds.filter((x) => x.isOffered); - }); + const possibleDenoms = await getCandidateWithdrawalDenoms( + ws, + exchangeBaseUrl, + instructedAmount.currency, + ); let versionMatch; - if (exchangeDetails.protocolVersionRange) { + if (exchange.protocolVersionRange) { versionMatch = LibtoolVersion.compare( WALLET_EXCHANGE_PROTOCOL_VERSION, - exchangeDetails.protocolVersionRange, + exchange.protocolVersionRange, ); if ( @@ -1861,19 +1871,19 @@ export async function getExchangeWithdrawalInfo( ) { logger.warn( `wallet's support for exchange protocol version ${WALLET_EXCHANGE_PROTOCOL_VERSION} might be outdated ` + - `(exchange has ${exchangeDetails.protocolVersionRange}), checking for updates`, + `(exchange has ${exchange.protocolVersionRange}), checking for updates`, ); } } let tosAccepted = false; - if (exchangeDetails.tosAccepted?.timestamp) { - if (exchangeDetails.tosAccepted.etag === exchangeDetails.tosCurrentEtag) { + if (exchange.tosAcceptedTimestamp) { + if (exchange.tosAcceptedEtag === exchange.tosCurrentEtag) { tosAccepted = true; } } - const paytoUris = exchangeDetails.wireInfo.accounts.map((x) => x.payto_uri); + const paytoUris = exchange.wireInfo.accounts.map((x) => x.payto_uri); if (!paytoUris) { throw Error("exchange is in invalid state"); } @@ -1882,8 +1892,8 @@ export async function getExchangeWithdrawalInfo( earliestDepositExpiration, exchangePaytoUris: paytoUris, exchangeWireAccounts, - withdrawalAccountList, - exchangeVersion: exchangeDetails.protocolVersionRange || "unknown", + exchangeCreditAccountDetails: withdrawalAccountsList, + exchangeVersion: exchange.protocolVersionRange || "unknown", numOfferedDenoms: possibleDenoms.length, selectedDenoms, // FIXME: delete this field / replace by something we can display to the user @@ -1925,7 +1935,7 @@ export async function getWithdrawalDetailsForUri( // FIXME: right now the exchange gets permanently added, // we might want to only temporarily add it. try { - await ws.exchangeOps.updateExchangeFromUrl(ws, info.suggestedExchange); + await ws.exchangeOps.fetchFreshExchange(ws, info.suggestedExchange); } catch (e) { // We still continued if it failed, as other exchanges might be available. // We don't want to fail if the bank-suggested exchange is broken/offline. @@ -1954,13 +1964,10 @@ export async function getWithdrawalDetailsForUri( tx, r.baseUrl, ); - const denominations = await tx.denominations.indexes.byExchangeBaseUrl - .iter(r.baseUrl) - .toArray(); const retryRecord = await tx.operationRetries.get( TaskIdentifiers.forExchangeUpdate(r), ); - if (exchangeDetails && denominations) { + if (exchangeDetails) { exchanges.push( makeExchangeListItem(r, exchangeDetails, retryRecord?.lastError), ); @@ -2105,10 +2112,8 @@ async function registerReserveWithBank( body: reqBody, timeout: getReserveRequestTimeout(withdrawalGroup), }); - await readSuccessResponseJsonOrThrow( - httpResp, - codecForBankWithdrawalOperationPostResponse(), - ); + // FIXME: libeufin-bank currently doesn't return a response in the right format, so we don't validate at all. + await readSuccessResponseJsonOrThrow(httpResp, codecForAny()); const transitionInfo = await ws.db .mktx((x) => [x.withdrawalGroups]) .runReadWrite(async (tx) => { @@ -2262,7 +2267,7 @@ async function processReserveBankStatus( r.wgInfo.bankInfo.timestampBankConfirmed = timestampPreciseToDb(now); r.status = WithdrawalGroupStatus.PendingQueryingStatus; } else { - logger.info("withdrawal: transfer not yet confirmed by bank"); + logger.trace("withdrawal: transfer not yet confirmed by bank"); r.wgInfo.bankInfo.confirmUrl = status.confirm_transfer_url; r.senderWire = status.sender_wire; } @@ -2293,7 +2298,6 @@ export interface PrepareCreateWithdrawalGroupResult { creationInfo?: { amount: AmountJson; canonExchange: string; - exchangeDetails: ExchangeDetailsRecord; }; } @@ -2316,6 +2320,7 @@ export async function internalPrepareCreateWithdrawalGroup( const secretSeed = encodeCrock(getRandomBytes(32)); const canonExchange = canonicalizeBaseUrl(args.exchangeBaseUrl); const amount = args.amount; + const currency = Amounts.currencyOf(amount); let withdrawalGroupId; @@ -2340,7 +2345,11 @@ export async function internalPrepareCreateWithdrawalGroup( } await updateWithdrawalDenoms(ws, canonExchange); - const denoms = await getCandidateWithdrawalDenoms(ws, canonExchange); + const denoms = await getCandidateWithdrawalDenoms( + ws, + canonExchange, + currency, + ); let initialDenomSel: DenomSelectionState; const denomSelUid = encodeCrock(getRandomBytes(16)); @@ -2379,8 +2388,7 @@ export async function internalPrepareCreateWithdrawalGroup( wgInfo: args.wgInfo, }; - const exchangeInfo = await updateExchangeFromUrl(ws, canonExchange); - const exchangeDetails = exchangeInfo.exchangeDetails; + const exchangeInfo = await fetchFreshExchange(ws, canonExchange); const transactionId = constructTransactionIdentifier({ tag: TransactionType.Withdrawal, withdrawalGroupId: withdrawalGroup.withdrawalGroupId, @@ -2392,7 +2400,6 @@ export async function internalPrepareCreateWithdrawalGroup( creationInfo: { canonExchange, amount, - exchangeDetails, }, }; } @@ -2415,8 +2422,6 @@ export async function internalPerformCreateWithdrawalGroup( if (!prep.creationInfo) { return { withdrawalGroup, transitionInfo: undefined }; } - const { amount, canonExchange, exchangeDetails } = prep.creationInfo; - await tx.withdrawalGroups.add(withdrawalGroup); await tx.reserves.put({ reservePub: withdrawalGroup.reservePub, @@ -2522,7 +2527,7 @@ export async function acceptWithdrawalFromUri( }; } - await updateExchangeFromUrl(ws, selectedExchange); + await fetchFreshExchange(ws, selectedExchange); const withdrawInfo = await getBankWithdrawalInfo( ws.http, req.talerWithdrawUri, @@ -2533,11 +2538,22 @@ export async function acceptWithdrawalFromUri( withdrawInfo.wireTypes, ); + const exchange = await ws.exchangeOps.fetchFreshExchange( + ws, + selectedExchange, + ); + + const withdrawalAccountList = await fetchWithdrawalAccountInfo(ws, { + exchange, + instructedAmount: withdrawInfo.amount, + }); + const withdrawalGroup = await internalCreateWithdrawalGroup(ws, { amount: withdrawInfo.amount, exchangeBaseUrl: req.selectedExchange, wgInfo: { withdrawalType: WithdrawalRecordType.BankIntegrated, + exchangeCreditAccounts: withdrawalAccountList, bankInfo: { exchangePaytoUri, talerWithdrawUri: req.talerWithdrawUri, @@ -2581,6 +2597,76 @@ export async function acceptWithdrawalFromUri( }; } +async function fetchAccount( + ws: InternalWalletState, + instructedAmount: AmountJson, + acct: ExchangeWireAccount, + reservePub?: string, +): Promise<WithdrawalExchangeAccountDetails> { + let paytoUri: string; + let transferAmount: AmountString | undefined = undefined; + let currencySpecification: CurrencySpecification | undefined = undefined; + if (acct.conversion_url != null) { + const reqUrl = new URL("cashin-rate", acct.conversion_url); + reqUrl.searchParams.set( + "amount_credit", + Amounts.stringify(instructedAmount), + ); + const httpResp = await ws.http.fetch(reqUrl.href); + const respOrErr = await readSuccessResponseJsonOrErrorCode( + httpResp, + codecForCashinConversionResponse(), + ); + if (respOrErr.isError) { + return { + status: "error", + paytoUri: acct.payto_uri, + conversionError: respOrErr.talerErrorResponse, + }; + } + const resp = respOrErr.response; + paytoUri = acct.payto_uri; + transferAmount = resp.amount_debit; + const configUrl = new URL("config", acct.conversion_url); + const configResp = await ws.http.fetch(configUrl.href); + const configRespOrError = await readSuccessResponseJsonOrErrorCode( + configResp, + codecForConversionBankConfig(), + ); + if (configRespOrError.isError) { + return { + status: "error", + paytoUri: acct.payto_uri, + conversionError: configRespOrError.talerErrorResponse, + }; + } + const configParsed = configRespOrError.response; + currencySpecification = configParsed.fiat_currency_specification; + } else { + paytoUri = acct.payto_uri; + transferAmount = Amounts.stringify(instructedAmount); + } + paytoUri = addPaytoQueryParams(paytoUri, { + amount: Amounts.stringify(transferAmount), + }); + if (reservePub != null) { + paytoUri = addPaytoQueryParams(paytoUri, { + message: `Taler Withdrawal ${reservePub}`, + }); + } + const acctInfo: WithdrawalExchangeAccountDetails = { + status: "ok", + paytoUri, + transferAmount, + currencySpecification, + creditRestrictions: acct.credit_restrictions, + }; + if (transferAmount != null) { + acctInfo.transferAmount = transferAmount; + } + return acctInfo; +} + /** * Gather information about bank accounts that can be used for * withdrawals. This includes accounts that are in a different @@ -2589,47 +2675,20 @@ export async function acceptWithdrawalFromUri( async function fetchWithdrawalAccountInfo( ws: InternalWalletState, req: { - exchangeDetails: ExchangeDetailsRecord; + exchange: ReadyExchangeSummary; instructedAmount: AmountJson; reservePub?: string; }, -): Promise<WithdrawalAccountInfo[]> { - const { exchangeDetails, instructedAmount } = req; - const withdrawalAccounts: WithdrawalAccountInfo[] = []; - for (let acct of exchangeDetails.wireInfo.accounts) { - let paytoUri: string; - let transferAmount: AmountString; - if (acct.conversion_url != null) { - const reqUrl = new URL("cashin-rate", acct.conversion_url); - reqUrl.searchParams.set( - "amount_credit", - Amounts.stringify(instructedAmount), - ); - const httpResp = await ws.http.fetch(reqUrl.href); - const resp = await readSuccessResponseJsonOrThrow( - httpResp, - codecForCashinConversionResponse(), - ); - paytoUri = acct.payto_uri; - transferAmount = resp.amount_debit; - if (req.reservePub) { - } - } else { - paytoUri = acct.payto_uri; - transferAmount = Amounts.stringify(instructedAmount); - } - paytoUri = addPaytoQueryParams(paytoUri, { - amount: Amounts.stringify(transferAmount), - }); - if (req.reservePub != null) { - paytoUri = addPaytoQueryParams(paytoUri, { - message: `Taler Withdrawal ${req.reservePub}`, - }); - } - const acctInfo: WithdrawalAccountInfo = { - paytoUri, - transferAmount, - }; +): Promise<WithdrawalExchangeAccountDetails[]> { + const { exchange, instructedAmount } = req; + const withdrawalAccounts: WithdrawalExchangeAccountDetails[] = []; + for (let acct of exchange.wireInfo.accounts) { + const acctInfo = await fetchAccount( + ws, + req.instructedAmount, + acct, + req.reservePub, + ); withdrawalAccounts.push(acctInfo); } return withdrawalAccounts; @@ -2654,12 +2713,9 @@ export async function createManualWithdrawal( ): Promise<AcceptManualWithdrawalResult> { const { exchangeBaseUrl } = req; const amount = Amounts.parseOrThrow(req.amount); - const { exchangeDetails } = await ws.exchangeOps.updateExchangeFromUrl( - ws, - exchangeBaseUrl, - ); + const exchange = await ws.exchangeOps.fetchFreshExchange(ws, exchangeBaseUrl); - if (exchangeDetails.currency != amount.currency) { + if (exchange.currency != amount.currency) { throw Error( "manual withdrawal with conversion from foreign currency is not yet supported", ); @@ -2668,8 +2724,8 @@ export async function createManualWithdrawal( {}, ); - const withdrawalAccountList = await fetchWithdrawalAccountInfo(ws, { - exchangeDetails, + const withdrawalAccountsList = await fetchWithdrawalAccountInfo(ws, { + exchange, instructedAmount: amount, reservePub: reserveKeyPair.pub, }); @@ -2678,7 +2734,7 @@ export async function createManualWithdrawal( amount: Amounts.jsonifyAmount(req.amount), wgInfo: { withdrawalType: WithdrawalRecordType.BankManual, - exchangeCreditAccounts: withdrawalAccountList, + exchangeCreditAccounts: withdrawalAccountsList, }, exchangeBaseUrl: req.exchangeBaseUrl, forcedDenomSel: req.forcedDenomSel, @@ -2704,7 +2760,7 @@ export async function createManualWithdrawal( return { reservePub: withdrawalGroup.reservePub, exchangePaytoUris: exchangePaytoUris, - withdrawalAccountsList: withdrawalAccountList, + withdrawalAccountsList: withdrawalAccountsList, transactionId, }; } diff --git a/packages/taler-wallet-core/src/util/coinSelection.test.ts b/packages/taler-wallet-core/src/util/coinSelection.test.ts @@ -19,9 +19,10 @@ import { Amounts, DenomKeyType, Duration, + TalerProtocolTimestamp, j2s, } from "@gnu-taler/taler-util"; -import test, { ExecutionContext } from "ava"; +import test from "ava"; import { AvailableDenom, testing_greedySelectPeer, @@ -31,6 +32,7 @@ import { const inTheDistantFuture = AbsoluteTime.toProtocolTimestamp( AbsoluteTime.addDuration(AbsoluteTime.now(), Duration.fromSpec({ hours: 1 })), ); + const inThePast = AbsoluteTime.toProtocolTimestamp( AbsoluteTime.subtractDuraction( AbsoluteTime.now(), @@ -60,16 +62,20 @@ test("p2p: should select the coin", (t) => { t.log(j2s(coins)); - expect(t, coins).deep.equal({ + t.assert(coins != null); + + t.deepEqual(coins, { "hash0;32;http://exchange.localhost/": { exchangeBaseUrl: "http://exchange.localhost/", denomPubHash: "hash0", maxAge: 32, contributions: [Amounts.parseOrThrow("LOCAL:2.1")], + expireDeposit: inTheDistantFuture, + expireWithdraw: inTheDistantFuture, }, }); - expect(t, tally).deep.equal({ + t.deepEqual(tally, { amountAcc: Amounts.parseOrThrow("LOCAL:2"), depositFeesAcc: Amounts.parseOrThrow("LOCAL:0.1"), lastDepositFee: Amounts.parseOrThrow("LOCAL:0.1"), @@ -96,7 +102,7 @@ test("p2p: should select 3 coins", (t) => { tally, ); - expect(t, coins).deep.equal({ + t.deepEqual(coins, { "hash0;32;http://exchange.localhost/": { exchangeBaseUrl: "http://exchange.localhost/", denomPubHash: "hash0", @@ -106,10 +112,12 @@ test("p2p: should select 3 coins", (t) => { Amounts.parseOrThrow("LOCAL:9.9"), Amounts.parseOrThrow("LOCAL:0.5"), ], + expireDeposit: inTheDistantFuture, + expireWithdraw: inTheDistantFuture, }, }); - expect(t, tally).deep.equal({ + t.deepEqual(tally, { amountAcc: Amounts.parseOrThrow("LOCAL:20"), depositFeesAcc: Amounts.parseOrThrow("LOCAL:0.3"), lastDepositFee: Amounts.parseOrThrow("LOCAL:0.1"), @@ -136,9 +144,9 @@ test("p2p: can't select since the instructed amount is too high", (t) => { tally, ); - expect(t, coins).deep.equal(undefined); + t.is(coins, undefined); - expect(t, tally).deep.equal({ + t.deepEqual(tally, { amountAcc: Amounts.parseOrThrow("LOCAL:49"), depositFeesAcc: Amounts.parseOrThrow("LOCAL:0.5"), lastDepositFee: Amounts.parseOrThrow("LOCAL:0.1"), @@ -186,16 +194,18 @@ test("pay: select one coin to pay with fee", (t) => { tally, ); - expect(t, coins).deep.equal({ + t.deepEqual(coins, { "hash0;32;http://exchange.localhost/": { exchangeBaseUrl: "http://exchange.localhost/", denomPubHash: "hash0", maxAge: 32, contributions: [Amounts.parseOrThrow("LOCAL:2.2")], + expireDeposit: inTheDistantFuture, + expireWithdraw: inTheDistantFuture, }, }); - expect(t, tally).deep.equal({ + t.deepEqual(tally, { amountPayRemaining: Amounts.parseOrThrow("LOCAL:2"), amountWireFeeLimitRemaining: zero, amountDepositFeeLimitRemaining: zero, @@ -237,19 +247,3 @@ function createCandidates( }; }); } - -type Tester<T> = { - deep: { - equal(another: T): ReturnType<ExecutionContext["deepEqual"]>; - equals(another: T): ReturnType<ExecutionContext["deepEqual"]>; - }; -}; - -function expect<T>(t: ExecutionContext, thing: T): Tester<T> { - return { - deep: { - equal: (another: T) => t.deepEqual(thing, another), - equals: (another: T) => t.deepEqual(thing, another), - }, - }; -} diff --git a/packages/taler-wallet-core/src/util/coinSelection.ts b/packages/taler-wallet-core/src/util/coinSelection.ts @@ -51,10 +51,12 @@ import { PayMerchantInsufficientBalanceDetails, PayPeerInsufficientBalanceDetails, strcmp, + TalerProtocolTimestamp, UnblindedSignature, } from "@gnu-taler/taler-util"; import { DenominationRecord } from "../db.js"; import { + getAutoRefreshExecuteThreshold, getExchangeDetails, isWithdrawableDenom, WalletDbReadOnlyTransaction, @@ -369,7 +371,7 @@ export async function selectPayCoinsNew( selInfo.maxAge, CoinStatus.Fresh, ]; - logger.info(`query: ${j2s(query)}`); + logger.trace(`query: ${j2s(query)}`); const coins = await tx.coins.indexes.byExchangeDenomPubHashAndAgeAndStatus.getAll( query, @@ -416,6 +418,8 @@ interface SelResult { [avKey: string]: { exchangeBaseUrl: string; denomPubHash: string; + expireWithdraw: TalerProtocolTimestamp; + expireDeposit: TalerProtocolTimestamp; maxAge: number; contributions: AmountJson[]; }; @@ -426,6 +430,7 @@ export function testing_selectGreedy( ): ReturnType<typeof selectGreedy> { return selectGreedy(...args); } + function selectGreedy( req: SelectPayCoinRequestNg, candidateDenoms: AvailableDenom[], @@ -483,6 +488,8 @@ function selectGreedy( denomPubHash: denom.denomPubHash, exchangeBaseUrl: denom.exchangeBaseUrl, maxAge: denom.maxAge, + expireDeposit: denom.stampExpireDeposit, + expireWithdraw: denom.stampExpireWithdraw, }; } sd.contributions.push(...contributions); @@ -521,6 +528,8 @@ function selectForced( denomPubHash: aci.denomPubHash, exchangeBaseUrl: aci.exchangeBaseUrl, maxAge: aci.maxAge, + expireDeposit: aci.stampExpireDeposit, + expireWithdraw: aci.stampExpireWithdraw, }; } sd.contributions.push(Amounts.parseOrThrow(forcedCoin.value)); @@ -870,6 +879,8 @@ export interface PeerCoinSelectionDetails { * How much of the deposit fees is the customer paying? */ depositFees: AmountJson; + + maxExpirationDate: TalerProtocolTimestamp; } export type SelectPeerCoinsResult = @@ -1009,6 +1020,8 @@ function greedySelectPeer( denomPubHash: denom.denomPubHash, exchangeBaseUrl: denom.exchangeBaseUrl, maxAge: denom.maxAge, + expireDeposit: denom.stampExpireDeposit, + expireWithdraw: denom.stampExpireWithdraw, }; } sd.contributions.push(...contributions); @@ -1114,8 +1127,20 @@ export async function selectPeerCoins( ); if (selectedDenom) { + let minAutorefreshExecuteThreshold = TalerProtocolTimestamp.never(); for (const dph of Object.keys(selectedDenom)) { const selInfo = selectedDenom[dph]; + // Compute earliest time that a selected denom + // would have its coins auto-refreshed. + minAutorefreshExecuteThreshold = TalerProtocolTimestamp.min( + minAutorefreshExecuteThreshold, + AbsoluteTime.toProtocolTimestamp( + getAutoRefreshExecuteThreshold({ + stampExpireDeposit: selInfo.expireDeposit, + stampExpireWithdraw: selInfo.expireWithdraw, + }), + ), + ); const numRequested = selInfo.contributions.length; const query = [ selInfo.exchangeBaseUrl, @@ -1150,6 +1175,7 @@ export async function selectPeerCoins( exchangeBaseUrl: exch.baseUrl, coins: resCoins, depositFees: tally.depositFeesAcc, + maxExpirationDate: minAutorefreshExecuteThreshold, }; return { type: "success", result: res }; } diff --git a/packages/taler-wallet-core/src/util/instructedAmountConversion.ts b/packages/taler-wallet-core/src/util/instructedAmountConversion.ts @@ -220,6 +220,7 @@ async function getAvailableDenoms( let debitDeadline = AbsoluteTime.never(); //4.- filter coins restricted by age if (operationType === OperationType.Credit) { + // FIXME: Use denom groups instead of querying all denominations! const ds = await tx.denominations.indexes.byExchangeBaseUrl.getAll( exchangeBaseUrl, ); diff --git a/packages/taler-wallet-core/src/versions.ts b/packages/taler-wallet-core/src/versions.ts @@ -29,28 +29,42 @@ export const WALLET_EXCHANGE_PROTOCOL_VERSION = "17:0:0"; export const WALLET_MERCHANT_PROTOCOL_VERSION = "5:0:1"; /** - * Protocol version spoken with the bank. + * Protocol version spoken with the bank (bank integration API). * * Uses libtool's current:revision:age versioning. */ -export const WALLET_BANK_INTEGRATION_PROTOCOL_VERSION = "0:0:0"; +export const WALLET_BANK_INTEGRATION_PROTOCOL_VERSION = "1:0:0"; /** - * Semver of the wallet-core implementation. + * Protocol version spoken with the bank (corebank API). + * + * Uses libtool's current:revision:age versioning. + */ +export const WALLET_COREBANK_API_PROTOCOL_VERSION = "2:0:0"; + +/** + * Protocol version spoken with the bank (conversion API). + * + * Uses libtool's current:revision:age versioning. + */ +export const WALLET_BANK_CONVERSION_API_PROTOCOL_VERSION = "2:0:0"; + +/** + * Semver of the wallet-core API implementation. * Will be replaced with the value from package.json in a * post-compilation step (inside lib/). */ -export const WALLET_CORE_IMPLEMENTATION_VERSION = "1:0:0"; +export const WALLET_CORE_API_IMPLEMENTATION_VERSION = "3:0:2"; /** * Libtool rules: - * - * If the library source code has changed at all since the last update, + * + * If the library source code has changed at all since the last update, * then increment revision (‘c:r:a’ becomes ‘c:r+1:a’). * If any interfaces have been added, removed, or changed since the last * update, increment current, and set revision to 0. - * If any interfaces have been added since the last public release, then + * If any interfaces have been added since the last public release, then * increment age. - * If any interfaces have been removed or changed since the last public + * If any interfaces have been removed or changed since the last public * release, then set age to 0. - */ -\ No newline at end of file + */ diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts @@ -64,6 +64,8 @@ import { GetContractTermsDetailsRequest, GetCurrencySpecificationRequest, GetCurrencySpecificationResponse, + GetExchangeEntryByUrlRequest, + GetExchangeEntryByUrlResponse, GetExchangeTosRequest, GetExchangeTosResult, GetPlanForOperationRequest, @@ -80,7 +82,7 @@ import { KnownBankAccounts, ListExchangesForScopedCurrencyRequest, ListKnownBankAccountsRequest, - ManualWithdrawalDetails, + WithdrawalDetailsForAmount, PrepareDepositRequest, PrepareDepositResponse, PreparePayRequest, @@ -93,6 +95,8 @@ import { PrepareRefundRequest, PrepareRewardRequest, PrepareTipResult as PrepareRewardResult, + PrepareWithdrawExchangeRequest, + PrepareWithdrawExchangeResponse, RecoverStoredBackupRequest, RecoveryLoadRequest, RetryTransactionRequest, @@ -152,6 +156,7 @@ export enum WalletApiOperation { GetTransactionById = "getTransactionById", TestingGetSampleTransactions = "testingGetSampleTransactions", ListExchanges = "listExchanges", + GetExchangeEntryByUrl = "getExchangeEntryByUrl", ListKnownBankAccounts = "listKnownBankAccounts", AddKnownBankAccounts = "addKnownBankAccounts", ForgetKnownBankAccounts = "forgetKnownBankAccounts", @@ -228,6 +233,7 @@ export enum WalletApiOperation { UpdateExchangeEntry = "updateExchangeEntry", TestingWaitTasksProcessed = "testingWaitTasksProcessed", ListExchangesForScopedCurrency = "listExchangesForScopedCurrency", + PrepareWithdrawExchange = "prepareWithdrawExchange", } // group: Initialization @@ -442,7 +448,7 @@ export type ResumeTransactionOp = { export type GetWithdrawalDetailsForAmountOp = { op: WalletApiOperation.GetWithdrawalDetailsForAmount; request: GetWithdrawalDetailsForAmountRequest; - response: ManualWithdrawalDetails; + response: WithdrawalDetailsForAmount; }; /** @@ -571,6 +577,15 @@ export type ListExchangesForScopedCurrencyOp = { }; /** + * Prepare for withdrawing via a taler://withdraw-exchange URI. + */ +export type PrepareWithdrawExchangeOp = { + op: WalletApiOperation.PrepareWithdrawExchange; + request: PrepareWithdrawExchangeRequest; + response: PrepareWithdrawExchangeResponse; +}; + +/** * Add / force-update an exchange. */ export type AddExchangeOp = { @@ -634,6 +649,15 @@ export type GetExchangeDetailedInfoOp = { }; /** + * Get the current terms of a service of an exchange. + */ +export type GetExchangeEntryByUrlOp = { + op: WalletApiOperation.GetExchangeEntryByUrl; + request: GetExchangeEntryByUrlRequest; + response: GetExchangeEntryByUrlResponse; +}; + +/** * List currencies known to the wallet. */ export type ListCurrenciesOp = { @@ -1127,6 +1151,7 @@ export type WalletOperations = { [WalletApiOperation.SetExchangeTosAccepted]: SetExchangeTosAcceptedOp; [WalletApiOperation.GetExchangeTos]: GetExchangeTosOp; [WalletApiOperation.GetExchangeDetailedInfo]: GetExchangeDetailedInfoOp; + [WalletApiOperation.GetExchangeEntryByUrl]: GetExchangeEntryByUrlOp; [WalletApiOperation.PrepareDeposit]: PrepareDepositOp; [WalletApiOperation.GenerateDepositGroupTxId]: GenerateDepositGroupTxIdOp; [WalletApiOperation.CreateDepositGroup]: CreateDepositGroupOp; @@ -1168,6 +1193,7 @@ export type WalletOperations = { [WalletApiOperation.DeleteStoredBackup]: DeleteStoredBackupOp; [WalletApiOperation.RecoverStoredBackup]: RecoverStoredBackupsOp; [WalletApiOperation.UpdateExchangeEntry]: UpdateExchangeEntryOp; + [WalletApiOperation.PrepareWithdrawExchange]: PrepareWithdrawExchangeOp; }; export type WalletCoreRequestType< diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts @@ -33,28 +33,26 @@ import { CoreApiResponse, CreateStoredBackupResponse, DeleteStoredBackupRequest, - DenomOperationMap, DenominationInfo, Duration, - ExchangeDetailedResponse, - ExchangeListItem, - ExchangesListResponse, ExchangesShortListResponse, - FeeDescription, GetCurrencySpecificationResponse, - GetExchangeTosResult, InitResponse, KnownBankAccounts, KnownBankAccountsInfo, Logger, - ManualWithdrawalDetails, + WithdrawalDetailsForAmount, MerchantUsingTemplateDetails, NotificationType, + PrepareWithdrawExchangeRequest, + PrepareWithdrawExchangeResponse, RecoverStoredBackupRequest, RefreshReason, + ScopeType, StoredBackupList, TalerError, TalerErrorCode, + TalerUriAction, TaskThrottler, TestingWaitTransactionRequest, TransactionState, @@ -88,6 +86,7 @@ import { codecForGetBalanceDetailRequest, codecForGetContractTermsDetails, codecForGetCurrencyInfoRequest, + codecForGetExchangeEntryByUrlRequest, codecForGetExchangeTosRequest, codecForGetWithdrawalDetailsForAmountRequest, codecForGetWithdrawalDetailsForUri, @@ -106,6 +105,7 @@ import { codecForPreparePeerPushCreditRequest, codecForPrepareRefundRequest, codecForPrepareRewardRequest, + codecForPrepareWithdrawExchangeRequest, codecForRecoverStoredBackupRequest, codecForResumeTransaction, codecForRetryTransactionRequest, @@ -130,6 +130,7 @@ import { j2s, parsePayTemplateUri, parsePaytoUri, + parseTalerUri, sampleWalletCoreTransactions, setDangerousTimetravel, validateIban, @@ -186,7 +187,7 @@ import { getBalanceDetail, getBalances } from "./operations/balance.js"; import { TaskIdentifiers, TaskRunResult, - getExchangeTosStatus, + TaskRunResultType, makeExchangeListItem, runTaskWithErrorReporting, } from "./operations/common.js"; @@ -200,10 +201,11 @@ import { import { acceptExchangeTermsOfService, addPresetExchangeEntry, - downloadTosFromAcceptedFormat, + fetchFreshExchange, + getExchangeDetailedInfo, getExchangeDetails, - getExchangeRequestTimeout, - updateExchangeFromUrl, + getExchangeTos, + getExchanges, updateExchangeFromUrlHandler, } from "./operations/exchanges.js"; import { getMerchantInfo } from "./operations/merchants.js"; @@ -288,11 +290,6 @@ import { import { PendingTaskInfo, PendingTaskType } from "./pending-types.js"; import { assertUnreachable } from "./util/assertUnreachable.js"; import { - createTimeline, - selectBestForOverlappingDenominations, - selectMinimumFee, -} from "./util/denominations.js"; -import { convertDepositAmount, convertPeerPushAmount, convertWithdrawalAmount, @@ -312,8 +309,10 @@ import { } from "./util/query.js"; import { TimerAPI, TimerGroup } from "./util/timer.js"; import { + WALLET_BANK_CONVERSION_API_PROTOCOL_VERSION, WALLET_BANK_INTEGRATION_PROTOCOL_VERSION, - WALLET_CORE_IMPLEMENTATION_VERSION, + WALLET_COREBANK_API_PROTOCOL_VERSION, + WALLET_CORE_API_IMPLEMENTATION_VERSION, WALLET_EXCHANGE_PROTOCOL_VERSION, WALLET_MERCHANT_PROTOCOL_VERSION, } from "./versions.js"; @@ -511,14 +510,17 @@ async function runTaskLoop( if (!AbsoluteTime.isExpired(p.timestampDue)) { continue; } - logger.info(`running task ${p.id}`); - await runTaskWithErrorReporting(ws, p.id, async () => { + logger.trace(`running task ${p.id}`); + const res = await runTaskWithErrorReporting(ws, p.id, async () => { return await callOperationHandler(ws, p); }); - ws.notify({ - type: NotificationType.PendingOperationProcessed, - id: p.id, - }); + if (!(ws.stopped && res.type === TaskRunResultType.Error)) { + ws.notify({ + type: NotificationType.PendingOperationProcessed, + id: p.id, + taskResultType: res.type, + }); + } if (ws.stopped) { ws.isTaskLoopRunning = false; return { @@ -541,6 +543,7 @@ async function runTaskLoop( * already been applied. */ async function fillDefaults(ws: InternalWalletState): Promise<void> { + const notifications: WalletNotification[] = []; await ws.db .mktx((x) => [x.config, x.exchanges, x.exchangeDetails]) .runReadWrite(async (tx) => { @@ -551,55 +554,23 @@ async function fillDefaults(ws: InternalWalletState): Promise<void> { return; } for (const exch of ws.config.builtin.exchanges) { - await addPresetExchangeEntry( + const resp = await addPresetExchangeEntry( tx, exch.exchangeBaseUrl, exch.currencyHint, ); + if (resp.notification) { + notifications.push(resp.notification); + } } await tx.config.put({ key: ConfigRecordKey.CurrencyDefaultsApplied, value: true, }); }); -} - -/** - * Get the exchange ToS in the requested format. - * Try to download in the accepted format not cached. - */ -async function getExchangeTos( - ws: InternalWalletState, - exchangeBaseUrl: string, - acceptedFormat?: string[], -): Promise<GetExchangeTosResult> { - // FIXME: download ToS in acceptable format if passed! - const { exchangeDetails } = await updateExchangeFromUrl(ws, exchangeBaseUrl); - - const tosDownload = await downloadTosFromAcceptedFormat( - ws, - exchangeBaseUrl, - getExchangeRequestTimeout(), - acceptedFormat, - ); - - await ws.db - .mktx((x) => [x.exchanges, x.exchangeDetails]) - .runReadWrite(async (tx) => { - const d = await getExchangeDetails(tx, exchangeBaseUrl); - if (d) { - d.tosCurrentEtag = tosDownload.tosEtag; - await tx.exchangeDetails.put(d); - } - }); - - return { - acceptedEtag: exchangeDetails.tosAccepted?.etag, - currentEtag: tosDownload.tosEtag, - content: tosDownload.tosText, - contentType: tosDownload.tosContentType, - tosStatus: getExchangeTosStatus(exchangeDetails), - }; + for (const notif of notifications) { + ws.notify(notif); + } } /** @@ -672,185 +643,6 @@ async function forgetKnownBankAccounts( return; } -async function getExchanges( - ws: InternalWalletState, -): Promise<ExchangesListResponse> { - const exchanges: ExchangeListItem[] = []; - await ws.db - .mktx((x) => [ - x.exchanges, - x.exchangeDetails, - x.denominations, - x.operationRetries, - ]) - .runReadOnly(async (tx) => { - const exchangeRecords = await tx.exchanges.iter().toArray(); - for (const r of exchangeRecords) { - const exchangeDetails = await getExchangeDetails(tx, r.baseUrl); - const opRetryRecord = await tx.operationRetries.get( - TaskIdentifiers.forExchangeUpdate(r), - ); - exchanges.push( - makeExchangeListItem(r, exchangeDetails, opRetryRecord?.lastError), - ); - } - }); - return { exchanges }; -} - -async function getExchangeDetailedInfo( - ws: InternalWalletState, - exchangeBaseurl: string, -): Promise<ExchangeDetailedResponse> { - //TODO: should we use the forceUpdate parameter? - const exchange = await ws.db - .mktx((x) => [x.exchanges, x.exchangeDetails, x.denominations]) - .runReadOnly(async (tx) => { - const ex = await tx.exchanges.get(exchangeBaseurl); - const dp = ex?.detailsPointer; - if (!dp) { - return; - } - const { currency } = dp; - const exchangeDetails = await getExchangeDetails(tx, ex.baseUrl); - if (!exchangeDetails) { - return; - } - - const denominationRecords = - await tx.denominations.indexes.byExchangeBaseUrl - .iter(ex.baseUrl) - .toArray(); - - if (!denominationRecords) { - return; - } - - const denominations: DenominationInfo[] = denominationRecords.map((x) => - DenominationRecord.toDenomInfo(x), - ); - - return { - info: { - exchangeBaseUrl: ex.baseUrl, - currency, - paytoUris: exchangeDetails.wireInfo.accounts.map((x) => x.payto_uri), - auditors: exchangeDetails.auditors, - wireInfo: exchangeDetails.wireInfo, - globalFees: exchangeDetails.globalFees, - }, - denominations, - }; - }); - - if (!exchange) { - throw Error(`exchange with base url "${exchangeBaseurl}" not found`); - } - - const denoms = exchange.denominations.map((d) => ({ - ...d, - group: Amounts.stringifyValue(d.value), - })); - const denomFees: DenomOperationMap<FeeDescription[]> = { - deposit: createTimeline( - denoms, - "denomPubHash", - "stampStart", - "stampExpireDeposit", - "feeDeposit", - "group", - selectBestForOverlappingDenominations, - ), - refresh: createTimeline( - denoms, - "denomPubHash", - "stampStart", - "stampExpireWithdraw", - "feeRefresh", - "group", - selectBestForOverlappingDenominations, - ), - refund: createTimeline( - denoms, - "denomPubHash", - "stampStart", - "stampExpireWithdraw", - "feeRefund", - "group", - selectBestForOverlappingDenominations, - ), - withdraw: createTimeline( - denoms, - "denomPubHash", - "stampStart", - "stampExpireWithdraw", - "feeWithdraw", - "group", - selectBestForOverlappingDenominations, - ), - }; - - const transferFees = Object.entries( - exchange.info.wireInfo.feesForType, - ).reduce((prev, [wireType, infoForType]) => { - const feesByGroup = [ - ...infoForType.map((w) => ({ - ...w, - fee: Amounts.stringify(w.closingFee), - group: "closing", - })), - ...infoForType.map((w) => ({ ...w, fee: w.wireFee, group: "wire" })), - ]; - prev[wireType] = createTimeline( - feesByGroup, - "sig", - "startStamp", - "endStamp", - "fee", - "group", - selectMinimumFee, - ); - return prev; - }, {} as Record<string, FeeDescription[]>); - - const globalFeesByGroup = [ - ...exchange.info.globalFees.map((w) => ({ - ...w, - fee: w.accountFee, - group: "account", - })), - ...exchange.info.globalFees.map((w) => ({ - ...w, - fee: w.historyFee, - group: "history", - })), - ...exchange.info.globalFees.map((w) => ({ - ...w, - fee: w.purseFee, - group: "purse", - })), - ]; - - const globalFees = createTimeline( - globalFeesByGroup, - "signature", - "startDate", - "endDate", - "fee", - "group", - selectMinimumFee, - ); - - return { - exchange: { - ...exchange.info, - denomFees, - transferFees, - globalFees, - }, - }; -} - async function setCoinSuspended( ws: InternalWalletState, coinPub: string, @@ -1042,6 +834,31 @@ async function recoverStoredBackup( logger.info(`import done`); } +async function handlePrepareWithdrawExchange( + ws: InternalWalletState, + req: PrepareWithdrawExchangeRequest, +): Promise<PrepareWithdrawExchangeResponse> { + const parsedUri = parseTalerUri(req.talerUri); + if (parsedUri?.type !== TalerUriAction.WithdrawExchange) { + throw Error("expected a taler://withdraw-exchange URI"); + } + const exchangeBaseUrl = parsedUri.exchangeBaseUrl; + const exchange = await fetchFreshExchange(ws, exchangeBaseUrl); + if (exchange.masterPub != parsedUri.exchangePub) { + throw Error("mismatch of exchange master public key (URI vs actual)"); + } + if (parsedUri.amount) { + const amt = Amounts.parseOrThrow(parsedUri.amount); + if (amt.currency !== exchange.currency) { + throw Error("mismatch of currency (URI vs exchange)"); + } + } + return { + exchangeBaseUrl, + amount: parsedUri.amount, + }; +} + /** * Implementation of the "wallet-core" API. */ @@ -1133,20 +950,50 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>( } case WalletApiOperation.AddExchange: { const req = codecForAddExchangeRequest().decode(payload); - await updateExchangeFromUrl(ws, req.exchangeBaseUrl, { - checkMasterPub: req.masterPub, - forceNow: req.forceUpdate, + await fetchFreshExchange(ws, req.exchangeBaseUrl, { + expectedMasterPub: req.masterPub, }); return {}; } case WalletApiOperation.UpdateExchangeEntry: { const req = codecForUpdateExchangeEntryRequest().decode(payload); - await updateExchangeFromUrl(ws, req.exchangeBaseUrl, {}); + await fetchFreshExchange(ws, req.exchangeBaseUrl, { + forceUpdate: true, + }); return {}; } case WalletApiOperation.ListExchanges: { return await getExchanges(ws); } + case WalletApiOperation.GetExchangeEntryByUrl: { + const req = codecForGetExchangeEntryByUrlRequest().decode(payload); + const exchangeEntry = await ws.db + .mktx((x) => [ + x.exchanges, + x.exchangeDetails, + x.denominations, + x.operationRetries, + ]) + .runReadOnly(async (tx) => { + const exchangeRec = await tx.exchanges.get(req.exchangeBaseUrl); + if (!exchangeRec) { + throw Error("exchange not found"); + } + const exchangeDetails = await getExchangeDetails( + tx, + exchangeRec.baseUrl, + ); + const opRetryRecord = await tx.operationRetries.get( + TaskIdentifiers.forExchangeUpdate(exchangeRec), + ); + return makeExchangeListItem( + exchangeRec, + exchangeDetails, + opRetryRecord?.lastError, + ); + }); + return exchangeEntry; + } case WalletApiOperation.ListExchangesForScopedCurrency: { const req = codecForListExchangesForScopedCurrencyRequest().decode(payload); @@ -1209,14 +1056,21 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>( for (const x of wi.selectedDenoms.selectedDenoms) { numCoins += x.count; } - const resp: ManualWithdrawalDetails = { + const amt = Amounts.parseOrThrow(req.amount); + const resp: WithdrawalDetailsForAmount = { amountRaw: req.amount, amountEffective: Amounts.stringify(wi.selectedDenoms.totalCoinValue), paytoUris: wi.exchangePaytoUris, tosAccepted: wi.termsOfServiceAccepted, ageRestrictionOptions: wi.ageRestrictionOptions, - withdrawalAccountList: wi.withdrawalAccountList, + withdrawalAccountsList: wi.exchangeCreditAccountDetails, numCoins, + // FIXME: Once we have proper scope info support, return correct info here. + scopeInfo: { + type: ScopeType.Exchange, + currency: amt.currency, + url: req.exchangeBaseUrl, + }, }; return resp; } @@ -1259,7 +1113,12 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>( } case WalletApiOperation.GetExchangeTos: { const req = codecForGetExchangeTosRequest().decode(payload); - return getExchangeTos(ws, req.exchangeBaseUrl, req.acceptedFormat); + return getExchangeTos( + ws, + req.exchangeBaseUrl, + req.acceptedFormat, + req.acceptLanguage, + ); } case WalletApiOperation.GetContractTermsDetails: { const req = codecForGetContractTermsDetails().decode(payload); @@ -1274,7 +1133,10 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>( const req = codecForSharePaymentRequest().decode(payload); return await sharePayment(ws, req.merchantBaseUrl, req.orderId); } - + case WalletApiOperation.PrepareWithdrawExchange: { + const req = codecForPrepareWithdrawExchangeRequest().decode(payload); + return handlePrepareWithdrawExchange(ws, req); + } case WalletApiOperation.PreparePayForUri: { const req = codecForPreparePayRequest().decode(payload); return await preparePayForUri(ws, req.talerPayUri); @@ -1661,9 +1523,12 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>( export function getVersion(ws: InternalWalletState): WalletCoreVersion { const result: WalletCoreVersion = { hash: undefined, - version: WALLET_CORE_IMPLEMENTATION_VERSION, + version: WALLET_CORE_API_IMPLEMENTATION_VERSION, exchange: WALLET_EXCHANGE_PROTOCOL_VERSION, merchant: WALLET_MERCHANT_PROTOCOL_VERSION, + bankConversionApiRange: WALLET_BANK_CONVERSION_API_PROTOCOL_VERSION, + bankIntegrationApiRange: WALLET_BANK_INTEGRATION_PROTOCOL_VERSION, + corebankApiRange: WALLET_COREBANK_API_PROTOCOL_VERSION, bank: WALLET_BANK_INTEGRATION_PROTOCOL_VERSION, devMode: false, }; @@ -1824,7 +1689,7 @@ class InternalWalletStateImpl implements InternalWalletState { exchangeOps: ExchangeOperations = { getExchangeDetails, - updateExchangeFromUrl, + fetchFreshExchange, }; recoupOps: RecoupOperations = { diff --git a/packages/taler-wallet-embedded/package.json b/packages/taler-wallet-embedded/package.json @@ -29,14 +29,14 @@ ], "devDependencies": { "@types/node": "^18.11.17", - "esbuild": "^0.17.7", - "prettier": "^2.8.8" + "esbuild": "^0.19.9", + "prettier": "^3.1.1" }, "dependencies": { + "@gnu-taler/anastasis-core": "workspace:*", "@gnu-taler/idb-bridge": "workspace:*", "@gnu-taler/taler-util": "workspace:*", "@gnu-taler/taler-wallet-core": "workspace:*", - "@gnu-taler/anastasis-core": "workspace:*", - "tslib": "^2.5.3" + "tslib": "^2.6.2" } } \ No newline at end of file diff --git a/packages/taler-wallet-embedded/src/wallet-qjs.ts b/packages/taler-wallet-embedded/src/wallet-qjs.ts @@ -146,24 +146,9 @@ class NativeWalletMessageHandler { throw Error("not implemented"); } case "reset": { - logger.info("resetting wallet"); - const oldArgs = this.walletArgs; - this.walletArgs = { ...oldArgs }; - if (oldArgs && oldArgs.persistentStoragePath) { - const ret = qjsOs.remove(oldArgs.persistentStoragePath); - if (ret != 0) { - logger.error("removing DB file failed"); - } - // Prevent further storage! - this.walletArgs.persistentStoragePath = undefined; - } - const wallet = await this.wp.promise; - wallet.stop(); - this.wp = openPromise<Wallet>(); - this.maybeWallet = undefined; - await reinit(); - logger.info("wallet re-initialized after reset"); - return wrapSuccessResponse({}); + throw Error( + "reset not supported anymore, please use the clearDb wallet-core request", + ); } default: { const wallet = await this.wp.promise; diff --git a/packages/taler-wallet-webextension/build.mjs b/packages/taler-wallet-webextension/build.mjs @@ -17,6 +17,7 @@ import { build } from "@gnu-taler/web-util/build"; import linaria from "@linaria/esbuild"; +import { shakerPlugin } from "@linaria/shaker"; await build({ type: "production", @@ -42,7 +43,7 @@ await build({ "@linaria", ], }, - sourceMap: true, + // sourceMap: true, }); }, }); diff --git a/packages/taler-wallet-webextension/linaria-esbuild-plugin-fixed.mjs b/packages/taler-wallet-webextension/linaria-esbuild-plugin-fixed.mjs @@ -1,108 +0,0 @@ -// src/index.ts -import fs from "fs"; -import path from "path"; -import { transformSync } from "esbuild"; -import { slugify, transform } from "@linaria/babel-preset"; -var nodeModulesRegex = /^(?:.*[\\/])?node_modules(?:[\\/].*)?$/; -function linaria({ sourceMap, preprocessor, esbuildOptions, ...rest } = {}) { - let options = esbuildOptions; - return { - name: "linaria", - setup(build) { - const cssLookup = /* @__PURE__ */ new Map(); - const asyncResolve = async (token, importer) => { - const context = path.isAbsolute(importer) - ? path.dirname(importer) - : path.join(process.cwd(), path.dirname(importer)); - const result = await build.resolve(token, { - resolveDir: context, - kind: "import-statement", - }); - if (result.errors.length > 0) { - throw new Error(`Cannot resolve ${token}`); - } - return result.path; - }; - build.onResolve({ filter: /\.linaria\.css$/ }, (args) => { - return { - namespace: "linaria", - path: args.path, - }; - }); - build.onLoad({ filter: /.*/, namespace: "linaria" }, (args) => { - return { - contents: cssLookup.get(args.path), - loader: "css", - resolveDir: path.basename(args.path), - }; - }); - build.onLoad({ filter: /\.(js|jsx|ts|tsx)$/ }, async (args) => { - const rawCode = fs.readFileSync(args.path, "utf8"); - const { ext, name: filename } = path.parse(args.path); - const loader = ext.replace(/^\./, ""); - if (nodeModulesRegex.test(args.path)) { - return { - loader, - contents: rawCode, - }; - } - if (!options) { - options = {}; - if ("jsxFactory" in build.initialOptions) { - options.jsxFactory = build.initialOptions.jsxFactory; - } - if ("jsxFragment" in build.initialOptions) { - options.jsxFragment = build.initialOptions.jsxFragment; - } - } - const transformed = transformSync(rawCode, { - ...options, - sourcefile: args.path, - sourcemap: sourceMap, - loader, - }); - let { code } = transformed; - if (sourceMap) { - const esbuildMap = Buffer.from(transformed.map).toString("base64"); - code += `/*# sourceMappingURL=data:application/json;base64,${esbuildMap}*/`; - } - const result = await transform( - code, - { - filename: args.path, - preprocessor, - pluginOptions: rest, - }, - asyncResolve - ); - if (!result.cssText) { - return { - contents: code, - loader, - resolveDir: path.dirname(args.path), - }; - } - let { cssText } = result; - const slug = slugify(cssText); - const cssFilename = `${filename}_${slug}.linaria.css`; - let contents = `import ${JSON.stringify(cssFilename)}; ${result.code}`; - if (sourceMap && result.cssSourceMapText) { - const map = Buffer.from(result.cssSourceMapText).toString("base64"); - cssText += `/*# sourceMappingURL=data:application/json;base64,${map}*/`; - const linariaMap = Buffer.from( - JSON.stringify(result.sourceMap) - ).toString("base64"); - contents += `/*# sourceMappingURL=data:application/json;base64,${linariaMap}*/`; - } - cssLookup.set(cssFilename, cssText); - return { - contents, - loader, - resolveDir: path.dirname(args.path), - }; - }); - }, - }; -} -export { linaria as default }; -//# sourceMappingURL=index.mjs.map diff --git a/packages/taler-wallet-webextension/manifest-v2.json b/packages/taler-wallet-webextension/manifest-v2.json @@ -18,6 +18,8 @@ "permissions": [ "unlimitedStorage", "storage", + "webRequest", + "<all_urls>", "activeTab" ], "web_accessible_resources": [ @@ -27,11 +29,19 @@ "dist/taler-wallet-interaction-support.js.map", "dist/taler-wallet-interaction-support.js" ], - "content_scripts": [{ - "matches": ["file://*/*", "http://*/*", "https://*/*"], - "js": ["dist/taler-wallet-interaction-loader.js"], - "run_at": "document_start" - }], + "content_scripts": [ + { + "matches": [ + "file://*/*", + "http://*/*", + "https://*/*" + ], + "js": [ + "dist/taler-wallet-interaction-loader.js" + ], + "run_at": "document_start" + } + ], "protocol_handlers": [ { "protocol": "ext+taler+http", diff --git a/packages/taler-wallet-webextension/manifest-v3.json b/packages/taler-wallet-webextension/manifest-v3.json @@ -17,9 +17,13 @@ "storage", "activeTab", "scripting", + "webRequest", "declarativeContent", "alarms" ], + "host_permissions": [ + "<all_urls>" + ], "commands": { "_execute_action": { "suggested_key": { diff --git a/packages/taler-wallet-webextension/package.json b/packages/taler-wallet-webextension/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/taler-wallet-webextension", - "version": "0.9.3-dev.34", + "version": "0.9.4-dev.2", "description": "GNU Taler Wallet browser extension", "main": "./build/index.js", "types": "./build/index.d.ts", @@ -12,7 +12,7 @@ "clean": "rm -rf dist lib tsconfig.tsbuildinfo", "test": "./test.mjs && mocha --require source-map-support/register 'dist/test/**/*.test.js' 'dist/test/**/test.js'", "test:coverage": "nyc pnpm test", - "compile": "./patch-linaria.sh && tsc && ./build.mjs", + "compile": "tsc && ./build.mjs", "typedoc": "typedoc --out dist/typedoc ./src/ --entryPointStrategy expand", "dev": "./dev.mjs", "pretty": "prettier --write src", @@ -30,7 +30,7 @@ "preact": "10.11.3", "preact-router": "3.2.1", "qrcode-generator": "^1.4.4", - "tslib": "^2.5.3" + "tslib": "^2.6.2" }, "eslintConfig": { "plugins": [ @@ -48,23 +48,24 @@ "@babel/preset-typescript": "7.18.6", "@gnu-taler/pogen": "workspace:*", "@gnu-taler/web-util": "workspace:*", - "@linaria/babel-preset": "^4.4.5", - "@linaria/core": "^4.2.10", - "@linaria/esbuild": "^4.2.11", - "@linaria/react": "^4.3.8", + "@linaria/babel-preset": "5.0.4", + "@linaria/core": "5.0.2", + "@linaria/esbuild": "5.0.4", + "@linaria/react": "5.0.3", + "@linaria/shaker": "5.0.3", "@types/chai": "^4.3.0", "@types/chrome": "0.0.197", "@types/history": "^4.7.8", "@types/mocha": "^9.0.0", "@types/node": "^18.11.17", "chai": "^4.3.6", - "esbuild": "^0.17.19", + "esbuild": "^0.19.9", "mocha": "^9.2.0", "nyc": "^15.1.0", "polished": "^4.1.4", "preact-cli": "^3.3.5", "preact-render-to-string": "^5.1.19", - "typescript": "5.2.2" + "typescript": "5.3.3" }, "nyc": { "include": [ @@ -75,4 +76,4 @@ "pogen": { "domain": "taler-wallet-webex" } -} -\ No newline at end of file +} diff --git a/packages/taler-wallet-webextension/patch-linaria.sh b/packages/taler-wallet-webextension/patch-linaria.sh @@ -1,9 +0,0 @@ -#!/bin/bash -# This file is in the public domain. - -# Fix: ERROR Cannot find module 'xxx' with esbuild 0.17 and linaria 4.2 -# remove when this PR is accepted -# https://github.com/callstack/linaria/pull/1256 - -cp linaria-esbuild-plugin-fixed.mjs ./node_modules/@linaria/esbuild/dist/index.mjs - diff --git a/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx @@ -18,56 +18,95 @@ import { AmountJson, Amounts, parsePaytoUri, - PaytoUri, segwitMinAmount, stringifyPaytoUri, TranslatedString, + WithdrawalExchangeAccountDetails } from "@gnu-taler/taler-util"; -import { Fragment, h, VNode } from "preact"; -import { useEffect, useRef, useState } from "preact/hooks"; import { - useAsyncAsHook, - useTranslationContext, + useTranslationContext } from "@gnu-taler/web-util/browser"; +import { ComponentChildren, Fragment, h, VNode } from "preact"; +import { useEffect, useRef, useState } from "preact/hooks"; import { CopiedIcon, CopyIcon } from "../svg/index.js"; import { Amount } from "./Amount.js"; import { ButtonBox, TooltipLeft, WarningBox } from "./styled/index.js"; -import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { useBackendContext } from "../context/backend.js"; +import { Button } from "../mui/Button.js"; export interface BankDetailsProps { - exchangeBaseUrl: string; subject: string; amount: AmountJson; + accounts: WithdrawalExchangeAccountDetails[], } export function BankDetailsByPaytoType({ subject, - exchangeBaseUrl, amount, + accounts, }: BankDetailsProps): VNode { const { i18n } = useTranslationContext(); - const api = useBackendContext(); - - const hook = useAsyncAsHook(async () => { - const details = await api.wallet.call( - WalletApiOperation.GetExchangeDetailedInfo, - { - exchangeBaseUrl, - }, - ); - return { details }; - }); - - if (!hook || hook.hasError) return <Fragment />; + const [index, setIndex] = useState(0) + const [currency, setCurrency] = useState(amount.currency) + if (!accounts.length) { + return <div>the exchange account list is empty</div> + } + const selectedAccount = accounts[index]; + const altCurrency = selectedAccount.currencySpecification?.name - const firstPayto = hook.response.details.exchange.paytoUris[0]; - const payto = parsePaytoUri(firstPayto); + const payto = parsePaytoUri(selectedAccount.paytoUri); if (!payto) return <Fragment />; - payto.params["amount"] = Amounts.stringify(amount); + payto.params["amount"] = currency === altCurrency ? selectedAccount.transferAmount! :Amounts.stringify(amount) ; payto.params["message"] = subject; + + function Frame({ title, children }: { title: TranslatedString, children: ComponentChildren }): VNode { + return <section + style={{ + textAlign: "left", + border: "solid 1px black", + padding: 8, + borderRadius: 4, + }} + > + <div style={{ display: "flex", width: "100%", justifyContent: "space-between" }}> + <p style={{ marginTop: 0 }}> + {title} + </p> + {accounts.length > 1 ? + <Button variant="contained" + onClick={async () => { + setIndex((index + 1) % accounts.length) + }} + > + <i18n.Translate>Next</i18n.Translate> + </Button> + : undefined} + </div> + + {children} + + {altCurrency ? + <Fragment> + <Button variant={currency === amount.currency ? "contained" : "outlined"} + onClick={async () => { + setCurrency(amount.currency) + }} + > + <i18n.Translate>{amount.currency}</i18n.Translate> + </Button> + <Button variant={currency === altCurrency ? "contained" : "outlined"} + onClick={async () => { + setCurrency(altCurrency) + }} + > + <i18n.Translate>{altCurrency}</i18n.Translate> + </Button> + </Fragment> + : undefined} + </section> + } + if (payto.isKnown && payto.targetType === "bitcoin") { const min = segwitMinAmount(amount.currency); const addrs = payto.segwitAddrs.map( @@ -76,17 +115,7 @@ export function BankDetailsByPaytoType({ addrs.unshift(`${payto.targetPath} ${Amounts.stringifyValue(amount)}`); const copyContent = addrs.join("\n"); return ( - <section - style={{ - textAlign: "left", - border: "solid 1px black", - padding: 8, - borderRadius: 4, - }} - > - <p style={{ marginTop: 0 }}> - <i18n.Translate>Bitcoin transfer details</i18n.Translate> - </p> + <Frame title={i18n.str`Bitcoin transfer details`}> <p> <i18n.Translate> The exchange need a transaction with 3 output, one output is the @@ -126,7 +155,7 @@ export function BankDetailsByPaytoType({ BTC, else you have to change the base unit to BTC </i18n.Translate> </p> - </section> + </Frame> ); } @@ -148,30 +177,30 @@ export function BankDetailsByPaytoType({ const receiver = payto.params["receiver"] || undefined; return ( - <section> - <div - style={{ - textAlign: "left", - border: "solid 1px black", - padding: 8, - borderRadius: 4, - }} - > - <p style={{ marginTop: 0 }}> - <i18n.Translate>Bank transfer details</i18n.Translate> - </p> - <table> - {accountPart} + <Frame title={i18n.str`Bank transfer details`}> + <table> + {accountPart} + {currency === altCurrency ? <Fragment> <Row name={i18n.str`Amount`} - value={<Amount value={amount} hideCurrency />} + value={<Amount value={selectedAccount.transferAmount!} />} /> - <Row name={i18n.str`Subject`} value={subject} literal /> - {receiver ? ( - <Row name={i18n.str`Receiver name`} value={receiver} /> - ) : undefined} - </table> - </div> + <Row + name={i18n.str`Converted`} + value={<Amount value={amount} />} + /> + + </Fragment> : + <Row + name={i18n.str`Amount`} + value={<Amount value={amount} />} + /> + } + <Row name={i18n.str`Subject`} value={subject} literal /> + {receiver ? ( + <Row name={i18n.str`Receiver name`} value={receiver} /> + ) : undefined} + </table> <table> <tbody> <tr> @@ -206,7 +235,7 @@ export function BankDetailsByPaytoType({ </i18n.Translate> </WarningBox> </p> - </section> + </Frame> ); } diff --git a/packages/taler-wallet-webextension/src/components/TermsOfService/index.ts b/packages/taler-wallet-webextension/src/components/TermsOfService/index.ts @@ -14,6 +14,7 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ +import { ExchangeListItem } from "@gnu-taler/taler-util"; import { Loading } from "../../components/Loading.js"; import { ErrorAlert } from "../../context/alert.js"; import { ToggleHandler } from "../../mui/handlers.js"; @@ -26,10 +27,13 @@ import { ShowButtonsNonAcceptedTosView, ShowTosContentView, } from "./views.js"; +import { ComponentChildren } from "preact"; export interface Props { exchangeUrl: string; - onChange?: (v: boolean) => void; + readOnly?: boolean; + showEvenIfaccepted?: boolean; + children: ComponentChildren; } export type State = @@ -56,13 +60,14 @@ export namespace State { } export interface ShowContent extends BaseInfo { status: "show-content"; - termsAccepted?: ToggleHandler; + termsAccepted: ToggleHandler; showingTermsOfService?: ToggleHandler; } export interface ShowButtonsAccepted extends BaseInfo { status: "show-buttons-accepted"; termsAccepted: ToggleHandler; showingTermsOfService: ToggleHandler; + children: ComponentChildren, } export interface ShowButtonsNotAccepted extends BaseInfo { status: "show-buttons-not-accepted"; diff --git a/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts b/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts @@ -23,10 +23,9 @@ import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; import { Props, State } from "./index.js"; import { buildTermsOfServiceState } from "./utils.js"; -export function useComponentState({ exchangeUrl, onChange }: Props): State { +export function useComponentState({ showEvenIfaccepted, exchangeUrl, readOnly, children }: Props): State { const api = useBackendContext(); - const readOnly = !onChange; - const [showContent, setShowContent] = useState<boolean>(readOnly); + const [showContent, setShowContent] = useState<boolean>(!!readOnly); const { i18n } = useTranslationContext(); const { pushAlertOnError } = useAlertContext(); @@ -79,8 +78,7 @@ export function useComponentState({ exchangeUrl, onChange }: Props): State { etag: undefined, }); } - // setAccepted(accepted); - if (!readOnly) onChange(accepted); //external update + terms?.retry() } const accepted = state.status === "accepted"; @@ -88,9 +86,9 @@ export function useComponentState({ exchangeUrl, onChange }: Props): State { const base = { error: undefined, showingTermsOfService: { - value: showContent, + value: showContent && (!accepted || showEvenIfaccepted), button: { - onClick: pushAlertOnError(async () => { + onClick: accepted && !showEvenIfaccepted ? undefined : pushAlertOnError(async () => { setShowContent(!showContent); }), }, @@ -99,7 +97,7 @@ export function useComponentState({ exchangeUrl, onChange }: Props): State { termsAccepted: { value: accepted, button: { - onClick: pushAlertOnError(async () => { + onClick: readOnly ? undefined : pushAlertOnError(async () => { const newValue = !accepted; //toggle await onUpdate(newValue); setShowContent(false); @@ -108,25 +106,27 @@ export function useComponentState({ exchangeUrl, onChange }: Props): State { }, }; - if (showContent) { - return { - status: "show-content", - error: undefined, - terms: state, - showingTermsOfService: readOnly ? undefined : base.showingTermsOfService, - termsAccepted: readOnly ? undefined : base.termsAccepted, - }; - } - //showing buttons if (accepted) { return { status: "show-buttons-accepted", ...base, + children, }; - } else { + } + + if ((accepted && showEvenIfaccepted) || showContent) { return { - status: "show-buttons-not-accepted", - ...base, + status: "show-content", + error: undefined, + terms: state, + showingTermsOfService: readOnly ? undefined : base.showingTermsOfService, + termsAccepted: base.termsAccepted, }; } + //showing buttons + return { + status: "show-buttons-not-accepted", + ...base, + }; + } diff --git a/packages/taler-wallet-webextension/src/components/TermsOfService/views.tsx b/packages/taler-wallet-webextension/src/components/TermsOfService/views.tsx @@ -20,7 +20,7 @@ import { CheckboxOutlined } from "../../components/CheckboxOutlined.js"; import { ExchangeXmlTos } from "../../components/ExchangeToS.js"; import { LinkSuccess, - TermsOfService, + TermsOfServiceStyle, WarningBox, WarningText, } from "../../components/styled/index.js"; @@ -31,35 +31,39 @@ import { State } from "./index.js"; export function ShowButtonsAcceptedTosView({ termsAccepted, showingTermsOfService, + children, }: State.ShowButtonsAccepted): VNode { const { i18n } = useTranslationContext(); - const ableToReviewTermsOfService = - showingTermsOfService.button.onClick !== undefined; return ( <Fragment> - {ableToReviewTermsOfService && ( - <section style={{ justifyContent: "space-around", display: "flex" }}> - <LinkSuccess - upperCased - onClick={showingTermsOfService.button.onClick} - > - <i18n.Translate>Show terms of service</i18n.Translate> - </LinkSuccess> - </section> + {showingTermsOfService.button.onClick !== undefined && ( + <Fragment> + <section style={{ justifyContent: "space-around", display: "flex" }}> + <LinkSuccess + upperCased + onClick={showingTermsOfService.button.onClick} + > + <i18n.Translate>Show terms of service</i18n.Translate> + </LinkSuccess> + </section> + {termsAccepted.button.onClick !== undefined && ( + <section style={{ justifyContent: "space-around", display: "flex" }}> + <CheckboxOutlined + name="terms" + enabled={termsAccepted.value} + label={ + <i18n.Translate> + I accept the exchange terms of service + </i18n.Translate> + } + onToggle={termsAccepted.button.onClick} + /> + </section> + )} + </Fragment> )} - <section style={{ justifyContent: "space-around", display: "flex" }}> - <CheckboxOutlined - name="terms" - enabled={termsAccepted.value} - label={ - <i18n.Translate> - I accept the exchange terms of service - </i18n.Translate> - } - onToggle={termsAccepted.button.onClick} - /> - </section> + {children} </Fragment> ); } @@ -99,15 +103,15 @@ export function ShowButtonsNonAcceptedTosView({ </WarningText> </section> )} */} - <section style={{ justifyContent: "space-around", display: "flex" }}> - <Button - variant="contained" - color="success" - onClick={showingTermsOfService.button.onClick} - > - <i18n.Translate>Review exchange terms of service</i18n.Translate> - </Button> - </section> + <section style={{ justifyContent: "space-around", display: "flex" }}> + <Button + variant="contained" + color="success" + onClick={showingTermsOfService.button.onClick} + > + <i18n.Translate>Review exchange terms of service</i18n.Translate> + </Button> + </section> </Fragment> ); } @@ -119,10 +123,10 @@ export function ShowTosContentView({ }: State.ShowContent): VNode { const { i18n } = useTranslationContext(); const ableToReviewTermsOfService = - showingTermsOfService?.button.onClick !== undefined; + termsAccepted.button.onClick !== undefined; return ( - <Fragment> + <section> {!terms.content && ( <section style={{ justifyContent: "space-around", display: "flex" }}> <WarningBox> @@ -143,9 +147,9 @@ export function ShowTosContentView({ </i18n.Translate> </WarningBox> ) : ( - <TermsOfService> + <TermsOfServiceStyle> <ExchangeXmlTos doc={terms.content.document} /> - </TermsOfService> + </TermsOfServiceStyle> ))} {terms.content.type === "plain" && (!terms.content.content ? ( @@ -179,7 +183,7 @@ export function ShowTosContentView({ </LinkSuccess> </section> )} - {termsAccepted && terms.status !== ExchangeTosStatus.Accepted && ( + {termsAccepted.button.onClick && terms.status !== ExchangeTosStatus.Accepted && ( <section style={{ justifyContent: "space-around", display: "flex" }}> <CheckboxOutlined name="terms" @@ -193,6 +197,6 @@ export function ShowTosContentView({ /> </section> )} - </Fragment> + </section> ); } diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx b/packages/taler-wallet-webextension/src/components/styled/index.tsx @@ -540,7 +540,7 @@ export const LinkPrimary = styled(Link)` color: black; `; -export const ButtonPrimary = styled(ButtonVariant)<{ small?: boolean }>` +export const ButtonPrimary = styled(ButtonVariant) <{ small?: boolean }>` font-size: ${({ small }: any) => (small ? "small" : "inherit")}; background-color: #0042b2; border-color: #0042b2; @@ -972,7 +972,7 @@ export const TermsSection = styled.a` } `; -export const TermsOfService = styled.div` +export const TermsOfServiceStyle = styled.div` display: flex; flex-direction: column; text-align: left; diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx @@ -34,6 +34,7 @@ import { InvoiceCreationDetails, } from "../../wallet/Transaction.js"; import { State } from "./index.js"; +import { TermsOfService } from "../../components/TermsOfService/index.js"; export function ReadyView({ exchangeUrl, @@ -151,9 +152,11 @@ export function ReadyView({ /> </section> <section> - <Button onClick={create.onClick} variant="contained" color="success"> - <i18n.Translate>Create</i18n.Translate> - </Button> + <TermsOfService key="terms" exchangeUrl={exchangeUrl} > + <Button onClick={create.onClick} variant="contained" color="success"> + <i18n.Translate>Create</i18n.Translate> + </Button> + </TermsOfService> </section> </Fragment> ); diff --git a/packages/taler-wallet-webextension/src/cta/Refund/views.tsx b/packages/taler-wallet-webextension/src/cta/Refund/views.tsx @@ -14,16 +14,13 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { Amounts } from "@gnu-taler/taler-util"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, h, VNode } from "preact"; import { Amount } from "../../components/Amount.js"; -import { LogoHeader } from "../../components/LogoHeader.js"; import { Part } from "../../components/Part.js"; -import { ProductList } from "../../components/ProductList.js"; -import { Link, SubTitle, WalletAction } from "../../components/styled/index.js"; -import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { Button } from "../../mui/Button.js"; import { State } from "./index.js"; +import { TermsOfService } from "../../components/TermsOfService/index.js"; export function IgnoredView(state: State.Ignored): VNode { const { i18n } = useTranslationContext(); diff --git a/packages/taler-wallet-webextension/src/cta/Reward/state.ts b/packages/taler-wallet-webextension/src/cta/Reward/state.ts @@ -64,7 +64,7 @@ export function useComponentState({ const doAccept = async (): Promise<void> => { const res = await api.wallet.call(WalletApiOperation.AcceptReward, { - walletRewardId: tip.walletRewardId, + walletRewardId: tip.transactionId, }); //FIX: this may not be seen since we are moving to the success also diff --git a/packages/taler-wallet-webextension/src/cta/Reward/views.tsx b/packages/taler-wallet-webextension/src/cta/Reward/views.tsx @@ -23,6 +23,7 @@ import { Link, SubTitle, WalletAction } from "../../components/styled/index.js"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { Button } from "../../mui/Button.js"; import { State } from "./index.js"; +import { TermsOfService } from "../../components/TermsOfService/index.js"; export function IgnoredView(state: State.Ignored): VNode { const { i18n } = useTranslationContext(); @@ -60,15 +61,17 @@ export function ReadyView(state: State.Ready): VNode { /> </section> <section> - <Button - variant="contained" - color="success" - onClick={state.accept.onClick} - > - <i18n.Translate> - Receive {<Amount value={state.amount} />} - </i18n.Translate> - </Button> + <TermsOfService key="terms" exchangeUrl={state.exchangeBaseUrl} > + <Button + variant="contained" + color="success" + onClick={state.accept.onClick} + > + <i18n.Translate> + Receive {<Amount value={state.amount} />} + </i18n.Translate> + </Button> + </TermsOfService> </section> </Fragment> ); diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts b/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts @@ -53,6 +53,7 @@ export namespace State { export interface Ready extends BaseInfo { status: "ready"; effective: AmountJson; + exchangeBaseUrl: string; raw: AmountJson; summary: string | undefined; expiration: AbsoluteTime | undefined; diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts @@ -61,6 +61,7 @@ export function useComponentState({ peerPushCreditId, amountEffective, amountRaw, + exchangeBaseUrl } = hook.response; const effective = Amounts.parseOrThrow(amountEffective); @@ -80,6 +81,7 @@ export function useComponentState({ return { status: "ready", effective, + exchangeBaseUrl, raw, error: undefined, accept: { diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/views.tsx b/packages/taler-wallet-webextension/src/cta/TransferPickup/views.tsx @@ -25,12 +25,14 @@ import { TransferPickupDetails, } from "../../wallet/Transaction.js"; import { State } from "./index.js"; +import { TermsOfService } from "../../components/TermsOfService/index.js"; export function ReadyView({ accept, summary, expiration, effective, + exchangeBaseUrl, raw, }: State.Ready): VNode { const { i18n } = useTranslationContext(); @@ -55,11 +57,13 @@ export function ReadyView({ /> </section> <section> - <Button variant="contained" color="success" onClick={accept.onClick}> - <i18n.Translate> - Receive {<Amount value={effective} />} - </i18n.Translate> - </Button> + <TermsOfService key="terms" exchangeUrl={exchangeBaseUrl} > + <Button variant="contained" color="success" onClick={accept.onClick}> + <i18n.Translate> + Receive {<Amount value={effective} />} + </i18n.Translate> + </Button> + </TermsOfService> </section> </Fragment> ); diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts @@ -17,7 +17,9 @@ import { AmountJson, AmountString, + CurrencySpecification, ExchangeListItem, + WithdrawalExchangeAccountDetails, } from "@gnu-taler/taler-util"; import { Loading } from "../../components/Loading.js"; import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js"; @@ -92,11 +94,18 @@ export namespace State { doWithdrawal: ButtonHandler; doSelectExchange: ButtonHandler; + chooseCurrencies: string[]; + selectedCurrency: string; + changeCurrency: (s: string) => void; + conversionInfo: { + spec: CurrencySpecification, + amount: AmountJson, + } | undefined; + ageRestriction?: SelectFieldHandler; talerWithdrawUri?: string; cancel: () => Promise<void>; - onTosUpdate: () => void; }; } diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts @@ -178,7 +178,6 @@ export function useComponentStateFromParams({ return () => exchangeSelectionState( - uriInfoHook.retry, doManualWithdraw, cancel, onSuccess, @@ -260,7 +259,6 @@ export function useComponentStateFromURI({ return () => exchangeSelectionState( - uriInfoHook.retry, doManagedWithdraw, cancel, onSuccess, @@ -277,7 +275,6 @@ type ManualOrManagedWithdrawFunction = ( ) => Promise<{ transactionId: string; confirmTransferUrl: string | undefined }>; function exchangeSelectionState( - onTosUpdate: () => void, doWithdraw: ManualOrManagedWithdrawFunction, cancel: () => Promise<void>, onSuccess: (txid: string) => Promise<void>, @@ -297,15 +294,13 @@ function exchangeSelectionState( return selectedExchange; } - return () => { + return (): State.Success | State.LoadingUriError | State.Loading => { const { i18n } = useTranslationContext(); const { pushAlertOnError } = useAlertContext(); const [ageRestricted, setAgeRestricted] = useState(0); const currentExchange = selectedExchange.selected; - const tosNeedToBeAccepted = - currentExchange.tosStatus == ExchangeTosStatus.Pending || - currentExchange.tosStatus == ExchangeTosStatus.Proposed; + const [selectedCurrency, setSelectedCurrency] = useState<string>(chosenAmount.currency) /** * With the exchange and amount, ask the wallet the information * about the withdrawal @@ -328,6 +323,7 @@ function exchangeSelectionState( return { amount: withdrawAmount, ageRestrictionOptions: info.ageRestrictionOptions, + accounts: info.withdrawalAccountsList }; }, []); @@ -400,24 +396,36 @@ function exchangeSelectionState( } : undefined; + const altCurrencies = amountHook.response.accounts.filter(a => !!a.currencySpecification).map(a => a.currencySpecification!.name) + const chooseCurrencies = altCurrencies.length === 0 ? [] : [toBeReceived.currency, ...altCurrencies] + const convAccount = amountHook.response.accounts.find(c => { + return c.currencySpecification && c.currencySpecification.name === selectedCurrency + }) + const conversionInfo = !convAccount ? undefined : ({ + spec: convAccount.currencySpecification!, + amount: Amounts.parseOrThrow(convAccount.transferAmount!) + }) + return { status: "success", error: undefined, doSelectExchange: selectedExchange.doSelect, currentExchange, toBeReceived, + chooseCurrencies, + selectedCurrency, + changeCurrency: (s) => { setSelectedCurrency(s) }, + conversionInfo, withdrawalFee, chosenAmount, talerWithdrawUri, ageRestriction, doWithdrawal: { onClick: - doingWithdraw || tosNeedToBeAccepted + doingWithdraw ? undefined : pushAlertOnError(doWithdrawAndCheckError), - error: withdrawError, }, - onTosUpdate, cancel, }; }; diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx @@ -19,7 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { ExchangeListItem } from "@gnu-taler/taler-util"; +import { CurrencySpecification, ExchangeListItem } from "@gnu-taler/taler-util"; import * as tests from "@gnu-taler/web-util/testing"; import { nullFunction } from "../../mui/handlers.js"; // import { TermsState } from "../../utils/index.js"; @@ -64,6 +64,7 @@ export const TermsOfServiceNotYetLoaded = tests.createExample(SuccessView, { fraction: 0, value: 1, }, + chooseCurrencies: [], }); export const WithSomeFee = tests.createExample(SuccessView, { @@ -90,6 +91,7 @@ export const WithSomeFee = tests.createExample(SuccessView, { value: 1, }, doSelectExchange: {}, + chooseCurrencies: [], }); export const WithoutFee = tests.createExample(SuccessView, { @@ -116,6 +118,7 @@ export const WithoutFee = tests.createExample(SuccessView, { fraction: 0, value: 2, }, + chooseCurrencies: [], }); export const EditExchangeUntouched = tests.createExample(SuccessView, { @@ -142,6 +145,7 @@ export const EditExchangeUntouched = tests.createExample(SuccessView, { fraction: 0, value: 2, }, + chooseCurrencies: [], }); export const EditExchangeModified = tests.createExample(SuccessView, { @@ -168,6 +172,7 @@ export const EditExchangeModified = tests.createExample(SuccessView, { fraction: 0, value: 2, }, + chooseCurrencies: [], }); export const WithAgeRestriction = tests.createExample(SuccessView, { @@ -195,4 +200,111 @@ export const WithAgeRestriction = tests.createExample(SuccessView, { fraction: 0, value: 2, }, + chooseCurrencies: [], +}); + +export const WithAlternateCurrenciesNETZBON = tests.createExample(SuccessView, { + error: undefined, + status: "success", + chosenAmount: { + currency: "NETZBON", + value: 2, + fraction: 10000000, + }, + chooseCurrencies: ["NETZBON", "EUR"], + selectedCurrency: "NETZBON", + doWithdrawal: { onClick: nullFunction }, + currentExchange: { + exchangeBaseUrl: "https://exchange.netzbon.ch", + tos: {}, + } as Partial<ExchangeListItem> as any, + withdrawalFee: { + currency: "NETZBON", + fraction: 10000000, + value: 1, + }, + doSelectExchange: {}, + toBeReceived: { + currency: "NETZBON", + fraction: 0, + value: 1, + }, +}); + +export const WithAlternateCurrenciesEURO = tests.createExample(SuccessView, { + error: undefined, + status: "success", + chosenAmount: { + currency: "NETZBON", + value: 2, + fraction: 10000000, + }, + chooseCurrencies: ["NETZBON", "EUR"], + selectedCurrency: "EUR", + changeCurrency: () => { }, + conversionInfo: { + spec: { + name: "EUR" + } as CurrencySpecification, + amount: { + currency: "EUR", + fraction: 10000000, + value: 1, + } + }, + doWithdrawal: { onClick: nullFunction }, + currentExchange: { + exchangeBaseUrl: "https://exchange.netzbon.ch", + tos: {}, + } as Partial<ExchangeListItem> as any, + withdrawalFee: { + currency: "NETZBON", + fraction: 10000000, + value: 1, + }, + doSelectExchange: {}, + toBeReceived: { + currency: "NETZBON", + fraction: 0, + value: 1, + }, +}); + +export const WithAlternateCurrenciesEURO11 = tests.createExample(SuccessView, { + error: undefined, + status: "success", + chosenAmount: { + currency: "NETZBON", + value: 2, + fraction: 10000000, + }, + chooseCurrencies: ["NETZBON", "EUR"], + selectedCurrency: "EUR", + changeCurrency: () => { }, + conversionInfo: { + spec: { + name: "EUR" + } as CurrencySpecification, + amount: { + currency: "EUR", + fraction: 10000000, + value: 2, + } + }, + doWithdrawal: { onClick: nullFunction }, + currentExchange: { + exchangeBaseUrl: "https://exchange.netzbon.ch", + tos: {}, + } as Partial<ExchangeListItem> as any, + withdrawalFee: { + currency: "NETZBON", + fraction: 10000000, + value: 1, + }, + doSelectExchange: {}, + toBeReceived: { + currency: "NETZBON", + fraction: 0, + value: 1, + }, }); diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts @@ -25,6 +25,7 @@ import { ExchangeEntryStatus, ExchangeListItem, ExchangeTosStatus, + ScopeType, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { expect } from "chai"; @@ -159,7 +160,12 @@ describe("Withdraw CTA states", () => { amountEffective: "ARS:2" as AmountString, paytoUris: ["payto://"], tosAccepted: true, - withdrawalAccountList: [], + scopeInfo: { + currency: "ARS", + type: ScopeType.Exchange, + url: "http://asd" + }, + withdrawalAccountsList: [], ageRestrictionOptions: [], numCoins: 42, }, @@ -194,7 +200,7 @@ describe("Withdraw CTA states", () => { expect(handler.getCallingQueueState()).eq("empty"); }); - it("should accept the tos before withdraw", async () => { + it.skip("should accept the tos before withdraw", async () => { const { handler, TestingContext } = createWalletApiMock(); const props = { talerWithdrawUri: "taler-withdraw://", @@ -223,8 +229,13 @@ describe("Withdraw CTA states", () => { amountRaw: "ARS:2" as AmountString, amountEffective: "ARS:2" as AmountString, paytoUris: ["payto://"], + scopeInfo: { + currency: "ARS", + type: ScopeType.Exchange, + url: "http://asd" + }, tosAccepted: false, - withdrawalAccountList: [], + withdrawalAccountsList: [], ageRestrictionOptions: [], numCoins: 42, }, @@ -259,18 +270,6 @@ describe("Withdraw CTA states", () => { expect(state.withdrawalFee).deep.equal(Amounts.parseOrThrow("ARS:0")); expect(state.chosenAmount).deep.equal(Amounts.parseOrThrow("ARS:2")); - expect(state.doWithdrawal.onClick).undefined; - - state.onTosUpdate(); - }, - (state) => { - expect(state.status).equals("success"); - if (state.status !== "success") return; - - expect(state.toBeReceived).deep.equal(Amounts.parseOrThrow("ARS:2")); - expect(state.withdrawalFee).deep.equal(Amounts.parseOrThrow("ARS:0")); - expect(state.chosenAmount).deep.equal(Amounts.parseOrThrow("ARS:2")); - expect(state.doWithdrawal.onClick).not.undefined; }, ], diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx @@ -37,8 +37,8 @@ import { AmountField } from "../../components/AmountField.js"; export function SuccessView(state: State.Success): VNode { const { i18n } = useTranslationContext(); - const currentTosVersionIsAccepted = - state.currentExchange.tosStatus === ExchangeTosStatus.Accepted; + // const currentTosVersionIsAccepted = + // state.currentExchange.tosStatus === ExchangeTosStatus.Accepted; return ( <Fragment> <section style={{ textAlign: "left" }}> @@ -66,10 +66,27 @@ export function SuccessView(state: State.Success): VNode { kind="neutral" big /> + {state.chooseCurrencies.length > 0 ? + <Fragment> + <p> + {state.chooseCurrencies.map(currency => { + return <Button variant={currency === state.selectedCurrency ? "contained" : "outlined"} + onClick={async () => { + state.changeCurrency(currency) + }} + > + {currency} + </Button> + })} + </p> + </Fragment> + : <Fragment />} + <Part title={i18n.str`Details`} text={ <WithdrawDetails + conversion={state.conversionInfo?.amount} amount={getAmountWithFee( state.toBeReceived, state.chosenAmount, @@ -92,7 +109,7 @@ export function SuccessView(state: State.Success): VNode { </section> <section> - {currentTosVersionIsAccepted ? ( + <TermsOfService exchangeUrl={state.currentExchange.exchangeBaseUrl}> <Button variant="contained" color="success" @@ -103,12 +120,7 @@ export function SuccessView(state: State.Success): VNode { Withdraw <Amount value={state.toBeReceived} /> </i18n.Translate> </Button> - ) : ( - <TermsOfService - exchangeUrl={state.currentExchange.exchangeBaseUrl} - onChange={state.onTosUpdate} - /> - )} + </TermsOfService> </section> {state.talerWithdrawUri ? ( <WithdrawWithMobile talerWithdrawUri={state.talerWithdrawUri} /> diff --git a/packages/taler-wallet-webextension/src/i18n/taler-wallet-webextension.pot b/packages/taler-wallet-webextension/src/i18n/taler-wallet-webextension.pot @@ -1,366 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-11-23 00:00+0100\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" -"Language-Team: LANGUAGE <LL@li.org>\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/NavigationBar.tsx:86 -#, c-format -msgid "Balance" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/NavigationBar.tsx:87 -#, c-format -msgid "Pending" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/NavigationBar.tsx:88 -#, c-format -msgid "Backup" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/NavigationBar.tsx:89 -#, c-format -msgid "Settings" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/NavigationBar.tsx:90 -#, c-format -msgid "Dev" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx:127 -#, c-format -msgid "Add provider" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx:137 -#, c-format -msgid "Sync all backups" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx:139 -#, c-format -msgid "Sync now" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/popup/BalancePage.tsx:79 -#, c-format -msgid "You have no balance to show. Need some %1$s getting started?" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx:145 -#, c-format -msgid "< Back" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx:156 -#, c-format -msgid "Next" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx:210 -#, c-format -msgid "< Back" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx:213 -#, c-format -msgid "Add provider" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:57 -#, c-format -msgid "Loading..." -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:64 -#, c-format -msgid "There was an error loading the provider detail for "%1$s"" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:75 -#, c-format -msgid "There is not known provider with url "%1$s". Redirecting back..." -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:131 -#, c-format -msgid "Back up" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:142 -#, c-format -msgid "Extend" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:148 -#, c-format -msgid "" -"terms has changed, extending the service will imply accepting the new terms of " -"service" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:158 -#, c-format -msgid "old" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:162 -#, c-format -msgid "new" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:169 -#, c-format -msgid "fee" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:177 -#, c-format -msgid "storage" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:190 -#, c-format -msgid "< back" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:194 -#, c-format -msgid "remove provider" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:213 -#, c-format -msgid "There is conflict with another backup from %1$s" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:228 -#, c-format -msgid "Unknown backup problem: %1$s" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx:247 -#, c-format -msgid "service paid" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/popup/Settings.tsx:46 -#, c-format -msgid "Permissions" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx:37 -#, c-format -msgid "Exchange doesn't have terms of service" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx:49 -#, c-format -msgid "Exchange doesn't have terms of service" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx:56 -#, c-format -msgid "Review exchange terms of service" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx:63 -#, c-format -msgid "Review new version of terms of service" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx:75 -#, c-format -msgid "Show terms of service" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx:83 -#, c-format -msgid "I accept the exchange terms of service" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx:127 -#, c-format -msgid "Hide terms of service" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx:136 -#, c-format -msgid "I accept the exchange terms of service" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx:110 -#, c-format -msgid "Cancel" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx:114 -#, c-format -msgid "Loading terms.." -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx:121 -#, c-format -msgid "Add exchange" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx:126 -#, c-format -msgid "Add exchange" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx:131 -#, c-format -msgid "Add exchange anyway" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx:133 -#, c-format -msgid "Cancel" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx:149 -#, c-format -msgid "Next" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx:83 -#, c-format -msgid "You have no balance to show. Need some %1$s getting started?" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx:104 -#, c-format -msgid "Add exchange" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx:144 -#, c-format -msgid "Add exchange" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/Settings.tsx:84 -#, c-format -msgid "Permissions" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/Settings.tsx:95 -#, c-format -msgid "Known exchanges" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/Transaction.tsx:154 -#, c-format -msgid "< Back" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/Transaction.tsx:159 -#, c-format -msgid "retry" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/Transaction.tsx:163 -#, c-format -msgid "Forget" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/Transaction.tsx:194 -#, c-format -msgid "Cancel" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/wallet/Transaction.tsx:198 -#, c-format -msgid "Confirm" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Pay.tsx:211 -#, c-format -msgid "Pay with a mobile phone" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Pay.tsx:211 -#, c-format -msgid "Hide QR" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Pay.tsx:241 -#, c-format -msgid "Pay" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Pay.tsx:265 -#, c-format -msgid "Withdraw digital cash" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Pay.tsx:295 -#, c-format -msgid "Digital cash payment" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Withdraw.tsx:101 -#, c-format -msgid "Digital cash withdrawal" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Withdraw.tsx:149 -#, c-format -msgid "Cancel exchange selection" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Withdraw.tsx:150 -#, c-format -msgid "Confirm exchange selection" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Withdraw.tsx:155 -#, c-format -msgid "Switch exchange" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Withdraw.tsx:174 -#, c-format -msgid "Confirm withdrawal" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Withdraw.tsx:183 -#, c-format -msgid "Withdraw anyway" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Withdraw.tsx:310 -#, c-format -msgid "missing withdraw uri" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Deposit.tsx:119 -#, c-format -msgid "Digital cash payment" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Deposit.tsx:133 -#, c-format -msgid "Digital cash payment" -msgstr "" - -#: /home/dold/repos/taler/wallet-core/packages/taler-wallet-webextension/src/cta/Deposit.tsx:186 -#, c-format -msgid "Digital cash deposit" -msgstr "" - diff --git a/packages/taler-wallet-webextension/src/i18n/tr.po b/packages/taler-wallet-webextension/src/i18n/tr.po @@ -17,8 +17,8 @@ msgstr "" "Project-Id-Version: Taler Wallet\n" "Report-Msgid-Bugs-To: languages@taler.net\n" "POT-Creation-Date: 2016-11-23 00:00+0100\n" -"PO-Revision-Date: 2023-03-06 22:06+0000\n" -"Last-Translator: Stefan <eintritt@hotmail.com>\n" +"PO-Revision-Date: 2023-12-05 21:51+0000\n" +"Last-Translator: Alp <berna.alp@digitalekho.com>\n" "Language-Team: Turkish <https://weblate.taler.net/projects/gnu-taler/" "webextensions/tr/>\n" "Language: tr\n" @@ -26,7 +26,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.13.1\n" +"X-Generator: Weblate 5.2.1\n" #: src/NavigationBar.tsx:139 #, c-format @@ -198,22 +198,22 @@ msgstr "" #: src/wallet/ProviderDetailPage.tsx:261 #, c-format msgid "Unknown backup problem: %1$s" -msgstr "" +msgstr "Bilinmeyen yedekleme problemi: %1$s" #: src/wallet/ProviderDetailPage.tsx:283 #, c-format msgid "service paid" -msgstr "" +msgstr "hizmet ödendi" #: src/wallet/ProviderDetailPage.tsx:290 #, c-format msgid "Backup valid until" -msgstr "" +msgstr "Yedekleme geçerlilik süresi" #: src/wallet/AddNewActionView.tsx:57 -#, fuzzy, c-format +#, c-format msgid "Cancel" -msgstr "Bakiye" +msgstr "İptal et" #: src/wallet/AddNewActionView.tsx:68 #, c-format @@ -243,7 +243,7 @@ msgstr "Para çekme sayfasını açın" #: src/popup/NoBalanceHelp.tsx:43 #, c-format msgid "Get digital cash" -msgstr "" +msgstr "Dijital para alın" #: src/popup/BalancePage.tsx:138 #, c-format @@ -253,12 +253,12 @@ msgstr "Bakiye sayfası yüklenemedi" #: src/popup/BalancePage.tsx:175 #, c-format msgid "Add" -msgstr "" +msgstr "Ekle" #: src/popup/BalancePage.tsx:179 -#, fuzzy, c-format +#, c-format msgid "Send %1$s" -msgstr "%1$s seçin" +msgstr "%1$s gönder" #: src/popup/TalerActionFound.tsx:44 #, c-format @@ -353,12 +353,12 @@ msgstr "" #: src/components/ShowFullContractTermPopup.tsx:234 #, c-format msgid "Merchant website" -msgstr "" +msgstr "Satıcı web sitesi" #: src/components/ShowFullContractTermPopup.tsx:240 #, c-format msgid "Merchant email" -msgstr "" +msgstr "Satıcı e-postası" #: src/components/ShowFullContractTermPopup.tsx:246 #, c-format diff --git a/packages/taler-wallet-webextension/src/platform/api.ts b/packages/taler-wallet-webextension/src/platform/api.ts @@ -46,9 +46,9 @@ export interface Permissions { * Compatibility API that works on multiple browsers. */ export interface CrossBrowserPermissionsApi { - // containsHostPermissions(): Promise<boolean>; - // requestHostPermissions(): Promise<boolean>; - // removeHostPermissions(): Promise<boolean>; + containsHostPermissions(): Promise<boolean>; + requestHostPermissions(): Promise<boolean>; + removeHostPermissions(): Promise<boolean>; containsClipboardPermissions(): Promise<boolean>; requestClipboardPermissions(): Promise<boolean>; @@ -207,6 +207,13 @@ export interface BackgroundPlatformAPI { ) => Promise<MessageResponse>, ): void; + /** + * Use by the wallet backend to activate the listener of HTTP request + */ + registerTalerHeaderListener(): void; + + containsTalerHeaderListener(): boolean; + } export interface ForegroundPlatformAPI { /** diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts b/packages/taler-wallet-webextension/src/platform/chrome.ts @@ -60,6 +60,8 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = { useServiceWorkerAsBackgroundProcess, keepAlive, listenNetworkConnectionState, + registerTalerHeaderListener, + containsTalerHeaderListener, }; export default api; @@ -149,6 +151,9 @@ function addPermissionsListener( function getPermissionsApi(): CrossBrowserPermissionsApi { return { + containsHostPermissions, + requestHostPermissions, + removeHostPermissions, addPermissionsListener, requestClipboardPermissions, removeClipboardPermissions, @@ -178,7 +183,6 @@ function openWalletURIFromPopup(uri: TalerUri): void { // the target pathname should handle what happens if the endpoint is not there // like "trying to open from popup but this uri is not handled" - encodeURIComponent; let url: string | undefined = undefined; switch (uri.type) { case TalerUriAction.WithdrawExchange: @@ -719,64 +723,72 @@ function listenNetworkConnectionState( }; } -// type HeaderListenerFunc = ( -// details: chrome.webRequest.WebResponseHeadersDetails, -// ) => void; -// let currentHeaderListener: HeaderListenerFunc | undefined = undefined; +type HeaderListenerFunc = ( + details: chrome.webRequest.WebResponseHeadersDetails, +) => void; +let currentHeaderListener: HeaderListenerFunc | undefined = undefined; // type TabListenerFunc = (tabId: number, info: chrome.tabs.TabChangeInfo) => void; // let currentTabListener: TabListenerFunc | undefined = undefined; -// function containsTalerHeaderListener(): boolean { -// return ( -// currentHeaderListener !== undefined || currentTabListener !== undefined -// ); -// } +function containsTalerHeaderListener(): boolean { + return ( + currentHeaderListener !== undefined + // || currentTabListener !== undefined + ); +} -// function headerListener( -// details: chrome.webRequest.WebResponseHeadersDetails, -// ): chrome.webRequest.BlockingResponse | undefined { -// if (chrome.runtime.lastError) { -// logger.error(JSON.stringify(chrome.runtime.lastError)); -// return; -// } -// console.log("HEADER", JSON.stringify(details, undefined, 2)) -// if ( -// details.statusCode === 402 || -// details.statusCode === 202 || -// details.statusCode === 200 -// ) { -// const values = (details.responseHeaders || []) -// .filter((h) => h.name.toLowerCase() === "taler") -// .map((h) => h.value) -// .filter((value): value is string => !!value); -// if (values.length > 0) { -// logger.info( -// `Found a Taler URI in a response header for the request ${details.url} from tab ${details.tabId}`, -// ); -// const redirectUrl = redirectTabToWalletPage(details.tabId, values[0]); -// return { redirectUrl } -// } -// } -// return details; -// } -// function parseTalerUriAndRedirect(tabId: number, maybeTalerUri: string): void { -// const talerUri = maybeTalerUri.startsWith("ext+") -// ? maybeTalerUri.substring(4) -// : maybeTalerUri; -// const uri = parseTalerUri(talerUri); -// if (!uri) { -// logger.warn( -// `Response with HTTP 402 the Taler header but could not classify ${talerUri}`, -// ); -// return; -// } -// redirectTabToWalletPage( -// tabId, -// `/taler-uri/${encodeURIComponent(talerUri)}`, -// ); -// } +function headerListener( + details: chrome.webRequest.WebResponseHeadersDetails, +): chrome.webRequest.BlockingResponse | undefined { + logger.info("header listener run", details.statusCode, chrome.runtime.lastError) + if (chrome.runtime.lastError) { + logger.error(JSON.stringify(chrome.runtime.lastError)); + return; + } + + if ( + details.statusCode === 402 || + details.statusCode === 202 || + details.statusCode === 200 + ) { + const values = (details.responseHeaders || []) + .filter((h) => h.name.toLowerCase() === "taler") + .map((h) => h.value) + .filter((value): value is string => !!value); + + const talerUri = values.length > 0 ? values[0] : undefined + if (talerUri) { + logger.info( + `Found a Taler URI in a response header for the request ${details.url} from tab ${details.tabId}: ${talerUri}`, + ); + parseTalerUriAndRedirect(details.tabId, talerUri); + return; + } + } + return details; +} +function parseTalerUriAndRedirect(tabId: number, maybeTalerUri: string): void { + const talerUri = maybeTalerUri.startsWith("ext+") + ? maybeTalerUri.substring(4) + : maybeTalerUri; + const uri = parseTalerUri(talerUri); + if (!uri) { + logger.warn( + `Response with HTTP 402 the Taler header but could not classify ${talerUri}`, + ); + return; + } + redirectTabToWalletPage( + tabId, + `/taler-uri/${encodeURIComponent(talerUri)}`, + ); +} + +/** + * Not needed anymore since SPA use taler support + */ // async function tabListener( // tabId: number, @@ -822,144 +834,142 @@ function listenNetworkConnectionState( // }); // } -// function registerTalerHeaderListener( -// ): void { -// logger.info("setting up header listener"); - -// const prevHeaderListener = currentHeaderListener; -// const prevTabListener = currentTabListener; - -// getPermissionsApi() -// .containsHostPermissions() -// .then((result) => { -// //if there is a handler already, remove it -// if ( -// prevHeaderListener && -// chrome?.webRequest?.onHeadersReceived?.hasListener(prevHeaderListener) -// ) { -// console.log("removming on header listener") -// chrome.webRequest.onHeadersReceived.removeListener(prevHeaderListener); -// // chrome.webRequest.onCompleted.removeListener(prevHeaderListener); -// // chrome.webRequest.onResponseStarted.removeListener(prevHeaderListener); -// // chrome.webRequest.onErrorOccurred.removeListener(prevHeaderListener); -// } -// if ( -// prevTabListener && -// chrome?.tabs?.onUpdated?.hasListener(prevTabListener) -// ) { -// console.log("removming on tab listener") -// chrome.tabs.onUpdated.removeListener(prevTabListener); -// } - -// //if the result was positive, add the headerListener -// if (result) { -// console.log("headers on, disabled:", chrome?.webRequest?.onHeadersReceived === undefined) -// if (chrome?.webRequest) { -// chrome.webRequest.onHeadersReceived.addListener(headerListener, -// { urls: ["<all_urls>"] }, -// ["responseHeaders", "extraHeaders"] -// ); -// // chrome.webRequest.onCompleted.addListener(headerListener, -// // { urls: ["<all_urls>"] }, -// // ["responseHeaders", "extraHeaders"] -// // ); -// // chrome.webRequest.onResponseStarted.addListener(headerListener, -// // { urls: ["<all_urls>"] }, -// // ["responseHeaders", "extraHeaders"] -// // ); -// // chrome.webRequest.onErrorOccurred.addListener(headerListener, -// // { urls: ["<all_urls>"] }, -// // ["extraHeaders"] -// // ); -// currentHeaderListener = headerListener; -// } - -// const tabsEvent: chrome.tabs.TabUpdatedEvent | undefined = -// chrome?.tabs?.onUpdated; -// if (tabsEvent) { -// tabsEvent.addListener(tabListener); -// currentTabListener = tabListener; -// } -// } else { -// console.log("headers off") -// } - -// //notify the browser about this change, this operation is expensive -// chrome?.webRequest?.handlerBehaviorChanged(() => { -// if (chrome.runtime.lastError) { -// logger.error(JSON.stringify(chrome.runtime.lastError)); -// } -// }); -// }); -// } +function registerTalerHeaderListener(): void { + logger.info("setting up header listener"); -// const hostPermissions = { -// permissions: ["webRequest"], -// origins: ["http://*/*", "https://*/*"], -// }; - -// export function containsHostPermissions(): Promise<boolean> { -// return new Promise((res, rej) => { -// chrome.permissions.contains(hostPermissions, (resp) => { -// const le = chrome.runtime.lastError?.message; -// if (le) { -// rej(le); -// } -// res(resp); -// }); -// }); -// } + const prevHeaderListener = currentHeaderListener; + // const prevTabListener = currentTabListener; -// export async function requestHostPermissions(): Promise<boolean> { -// return new Promise((res, rej) => { -// chrome.permissions.request(hostPermissions, (resp) => { -// const le = chrome.runtime.lastError?.message; -// if (le) { -// rej(le); -// } -// res(resp); -// }); -// }); -// } + if ( + prevHeaderListener && + chrome?.webRequest?.onHeadersReceived?.hasListener(prevHeaderListener) + ) { + return; + // console.log("removming on header listener") + // chrome.webRequest.onHeadersReceived.removeListener(prevHeaderListener); + // chrome.webRequest.onCompleted.removeListener(prevHeaderListener); + // chrome.webRequest.onResponseStarted.removeListener(prevHeaderListener); + // chrome.webRequest.onErrorOccurred.removeListener(prevHeaderListener); + } -// export async function removeHostPermissions(): Promise<boolean> { -// //if there is a handler already, remove it -// if ( -// currentHeaderListener && -// chrome?.webRequest?.onHeadersReceived?.hasListener(currentHeaderListener) -// ) { -// chrome.webRequest.onHeadersReceived.removeListener(currentHeaderListener); -// } -// if ( -// currentTabListener && -// chrome?.tabs?.onUpdated?.hasListener(currentTabListener) -// ) { -// chrome.tabs.onUpdated.removeListener(currentTabListener); -// } + // if ( + // prevTabListener && + // chrome?.tabs?.onUpdated?.hasListener(prevTabListener) + // ) { + // console.log("removming on tab listener") + // chrome.tabs.onUpdated.removeListener(prevTabListener); + // } + + console.log("headers on, disabled:", chrome?.webRequest?.onHeadersReceived === undefined) + if (chrome?.webRequest) { + if (extensionIsManifestV3()) { + chrome.webRequest.onHeadersReceived.addListener(headerListener, + { urls: ["<all_urls>"] }, + ["responseHeaders"] + ); + } else { + chrome.webRequest.onHeadersReceived.addListener(headerListener, + { urls: ["<all_urls>"] }, + ["responseHeaders"] + ); + } + // chrome.webRequest.onCompleted.addListener(headerListener, + // { urls: ["<all_urls>"] }, + // ["responseHeaders", "extraHeaders"] + // ); + // chrome.webRequest.onResponseStarted.addListener(headerListener, + // { urls: ["<all_urls>"] }, + // ["responseHeaders", "extraHeaders"] + // ); + // chrome.webRequest.onErrorOccurred.addListener(headerListener, + // { urls: ["<all_urls>"] }, + // ["extraHeaders"] + // ); + currentHeaderListener = headerListener; + } -// currentHeaderListener = undefined; -// currentTabListener = undefined; + // const tabsEvent: chrome.tabs.TabUpdatedEvent | undefined = + // chrome?.tabs?.onUpdated; + // if (tabsEvent) { + // tabsEvent.addListener(tabListener); + // currentTabListener = tabListener; + // } -// //notify the browser about this change, this operation is expensive -// if ("webRequest" in chrome) { -// chrome.webRequest.handlerBehaviorChanged(() => { -// if (chrome.runtime.lastError) { -// logger.error(JSON.stringify(chrome.runtime.lastError)); -// } -// }); -// } + //notify the browser about this change, this operation is expensive + chrome?.webRequest?.handlerBehaviorChanged(() => { + if (chrome.runtime.lastError) { + logger.error(JSON.stringify(chrome.runtime.lastError)); + } + }); +} -// if (extensionIsManifestV3()) { -// // Trying to remove host permissions with manifest >= v3 throws an error -// return true; -// } -// return new Promise((res, rej) => { -// chrome.permissions.remove(hostPermissions, (resp) => { -// const le = chrome.runtime.lastError?.message; -// if (le) { -// rej(le); -// } -// res(resp); -// }); -// }); -// } -\ No newline at end of file +const hostPermissions = { + permissions: ["webRequest"], + origins: ["http://*/*", "https://*/*"], +}; + +export function containsHostPermissions(): Promise<boolean> { + return new Promise((res, rej) => { + chrome.permissions.contains(hostPermissions, (resp) => { + const le = chrome.runtime.lastError?.message; + if (le) { + rej(le); + } + res(resp); + }); + }); +} + +export async function requestHostPermissions(): Promise<boolean> { + return new Promise((res, rej) => { + chrome.permissions.request(hostPermissions, (resp) => { + const le = chrome.runtime.lastError?.message; + if (le) { + rej(le); + } + res(resp); + }); + }); +} + +export async function removeHostPermissions(): Promise<boolean> { + //if there is a handler already, remove it + if ( + currentHeaderListener && + chrome?.webRequest?.onHeadersReceived?.hasListener(currentHeaderListener) + ) { + chrome.webRequest.onHeadersReceived.removeListener(currentHeaderListener); + } + // if ( + // currentTabListener && + // chrome?.tabs?.onUpdated?.hasListener(currentTabListener) + // ) { + // chrome.tabs.onUpdated.removeListener(currentTabListener); + // } + + currentHeaderListener = undefined; + // currentTabListener = undefined; + + //notify the browser about this change, this operation is expensive + if ("webRequest" in chrome) { + chrome.webRequest.handlerBehaviorChanged(() => { + if (chrome.runtime.lastError) { + logger.error(JSON.stringify(chrome.runtime.lastError)); + } + }); + } + + if (extensionIsManifestV3()) { + // Trying to remove host permissions with manifest >= v3 throws an error + return true; + } + return new Promise((res, rej) => { + chrome.permissions.remove(hostPermissions, (resp) => { + const le = chrome.runtime.lastError?.message; + if (le) { + rej(le); + } + res(resp); + }); + }); +} +\ No newline at end of file diff --git a/packages/taler-wallet-webextension/src/platform/dev.ts b/packages/taler-wallet-webextension/src/platform/dev.ts @@ -47,8 +47,8 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = { }), // registerDeclarativeRedirect: () => false, - // registerTalerHeaderListener: () => false, - // containsTalerHeaderListener: () => false, + registerTalerHeaderListener: () => false, + containsTalerHeaderListener: () => false, getWalletWebExVersion: () => ({ version: "none", }), diff --git a/packages/taler-wallet-webextension/src/platform/firefox.ts b/packages/taler-wallet-webextension/src/platform/firefox.ts @@ -26,9 +26,9 @@ import chromePlatform, { containsClipboardPermissions as chromeClipContains, removeClipboardPermissions as chromeClipRemove, requestClipboardPermissions as chromeClipRequest, - // containsHostPermissions as chromeHostContains, - // requestHostPermissions as chromeHostRequest, - // removeHostPermissions as chromeHostRemove, + containsHostPermissions as chromeHostContains, + requestHostPermissions as chromeHostRequest, + removeHostPermissions as chromeHostRemove, } from "./chrome.js"; const api: BackgroundPlatformAPI & ForegroundPlatformAPI = { @@ -48,15 +48,15 @@ function isFirefox(): boolean { } function addPermissionsListener(callback: (p: Permissions) => void): void { - throw Error("addPermissionListener is not supported for Firefox"); + // throw Error("addPermissionListener is not supported for Firefox"); } function getPermissionsApi(): CrossBrowserPermissionsApi { return { addPermissionsListener, - // containsHostPermissions: chromeHostContains, - // requestHostPermissions: chromeHostRequest, - // removeHostPermissions: chromeHostRemove, + containsHostPermissions: chromeHostContains, + requestHostPermissions: chromeHostRequest, + removeHostPermissions: chromeHostRemove, containsClipboardPermissions: chromeClipContains, removeClipboardPermissions: chromeClipRemove, requestClipboardPermissions: chromeClipRequest, diff --git a/packages/taler-wallet-webextension/src/taler-wallet-interaction-support.ts b/packages/taler-wallet-webextension/src/taler-wallet-interaction-support.ts @@ -137,6 +137,7 @@ function buildApi(config: Readonly<Info>): API { * Register the anchor handler when found */ function registerProtocolHandler() { + overrideAllAnchor(document.body) new MutationObserver(checkForNewAnchors).observe(document, { childList: true, subtree: true, diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts b/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts @@ -22,6 +22,7 @@ import { TextFieldHandler } from "../../mui/handlers.js"; import { compose, StateViewMap } from "../../utils/index.js"; import { useComponentState } from "./state.js"; import { ConfirmView, VerifyView } from "./views.js"; +import { ExchangeListItem } from "@gnu-taler/taler-util"; export interface Props { currency?: string; @@ -64,7 +65,7 @@ export namespace State { url: TextFieldHandler, knownExchanges: URL[], - result: HttpResponse<{ currency_specification: {currency: string}, version: string}, unknown> | undefined, + result: HttpResponse<{ currency_specification: { currency: string }, version: string }, unknown> | undefined, expectedCurrency: string | undefined, } } diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/test.ts b/packages/taler-wallet-webextension/src/wallet/AddExchange/test.ts @@ -26,7 +26,11 @@ import { Props } from "./index.js"; import { useComponentState } from "./state.js"; import { nullFunction } from "../../mui/handlers.js"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { ExchangeEntryStatus, ExchangeTosStatus, ExchangeUpdateStatus } from "@gnu-taler/taler-util"; +import { + ExchangeEntryStatus, + ExchangeTosStatus, + ExchangeUpdateStatus, +} from "@gnu-taler/taler-util"; const props: Props = { onBack: nullFunction, noDebounce: true, @@ -36,17 +40,24 @@ describe("AddExchange states", () => { it("should start in 'verify' state", async () => { const { handler, TestingContext } = createWalletApiMock(); - handler.addWalletCallResponse(WalletApiOperation.ListExchanges, {}, { - exchanges:[{ - exchangeBaseUrl: "http://exchange.local/", - ageRestrictionOptions: [], - currency: "ARS", - exchangeEntryStatus: ExchangeEntryStatus.Ephemeral, - tosStatus: ExchangeTosStatus.Pending, - exchangeUpdateStatus: ExchangeUpdateStatus.Failed, - paytoUris: [], - }] - }) + handler.addWalletCallResponse( + WalletApiOperation.ListExchanges, + {}, + { + exchanges: [ + { + exchangeBaseUrl: "http://exchange.local/", + ageRestrictionOptions: [], + scopeInfo: undefined, + currency: "ARS", + exchangeEntryStatus: ExchangeEntryStatus.Ephemeral, + tosStatus: ExchangeTosStatus.Pending, + exchangeUpdateStatus: ExchangeUpdateStatus.UnavailableUpdate, + paytoUris: [], + }, + ], + }, + ); const hookBehavior = await tests.hookBehaveLikeThis( useComponentState, @@ -57,7 +68,7 @@ describe("AddExchange states", () => { if (state.status !== "verify") return; expect(state.url.value).eq(""); expect(state.expectedCurrency).is.undefined; - expect(state.result).is.undefined; + expect(state.result).is.undefined; }, (state) => { expect(state.status).equal("verify"); @@ -74,22 +85,27 @@ describe("AddExchange states", () => { expect(handler.getCallingQueueState()).eq("empty"); }); - - it("should not be able to add a known exchange", async () => { const { handler, TestingContext } = createWalletApiMock(); - handler.addWalletCallResponse(WalletApiOperation.ListExchanges, {}, { - exchanges:[{ - exchangeBaseUrl: "http://exchange.local/", - ageRestrictionOptions: [], - currency: "ARS", - exchangeEntryStatus: ExchangeEntryStatus.Used, - tosStatus: ExchangeTosStatus.Pending, - exchangeUpdateStatus: ExchangeUpdateStatus.Ready, - paytoUris: [], - }] - }) + handler.addWalletCallResponse( + WalletApiOperation.ListExchanges, + {}, + { + exchanges: [ + { + exchangeBaseUrl: "http://exchange.local/", + ageRestrictionOptions: [], + scopeInfo: undefined, + currency: "ARS", + exchangeEntryStatus: ExchangeEntryStatus.Used, + tosStatus: ExchangeTosStatus.Pending, + exchangeUpdateStatus: ExchangeUpdateStatus.Ready, + paytoUris: [], + }, + ], + }, + ); const hookBehavior = await tests.hookBehaveLikeThis( useComponentState, @@ -100,7 +116,7 @@ describe("AddExchange states", () => { if (state.status !== "verify") return; expect(state.url.value).eq(""); expect(state.expectedCurrency).is.undefined; - expect(state.result).is.undefined; + expect(state.result).is.undefined; }, (state) => { expect(state.status).equal("verify"); @@ -111,7 +127,7 @@ describe("AddExchange states", () => { expect(state.error).is.undefined; expect(state.url.onInput).is.not.undefined; if (!state.url.onInput) return; - state.url.onInput("http://exchange.local/") + state.url.onInput("http://exchange.local/"); }, (state) => { expect(state.status).equal("verify"); @@ -130,21 +146,27 @@ describe("AddExchange states", () => { expect(handler.getCallingQueueState()).eq("empty"); }); - it("should be able to add a preset exchange", async () => { const { handler, TestingContext } = createWalletApiMock(); - handler.addWalletCallResponse(WalletApiOperation.ListExchanges, {}, { - exchanges:[{ - exchangeBaseUrl: "http://exchange.local/", - ageRestrictionOptions: [], - currency: "ARS", - exchangeEntryStatus: ExchangeEntryStatus.Preset, - tosStatus: ExchangeTosStatus.Pending, - exchangeUpdateStatus: ExchangeUpdateStatus.Ready, - paytoUris: [], - }] - }) + handler.addWalletCallResponse( + WalletApiOperation.ListExchanges, + {}, + { + exchanges: [ + { + exchangeBaseUrl: "http://exchange.local/", + ageRestrictionOptions: [], + scopeInfo: undefined, + currency: "ARS", + exchangeEntryStatus: ExchangeEntryStatus.Preset, + tosStatus: ExchangeTosStatus.Pending, + exchangeUpdateStatus: ExchangeUpdateStatus.Ready, + paytoUris: [], + }, + ], + }, + ); const hookBehavior = await tests.hookBehaveLikeThis( useComponentState, @@ -155,7 +177,7 @@ describe("AddExchange states", () => { if (state.status !== "verify") return; expect(state.url.value).eq(""); expect(state.expectedCurrency).is.undefined; - expect(state.result).is.undefined; + expect(state.result).is.undefined; }, (state) => { expect(state.status).equal("verify"); @@ -166,7 +188,7 @@ describe("AddExchange states", () => { expect(state.error).is.undefined; expect(state.url.onInput).is.not.undefined; if (!state.url.onInput) return; - state.url.onInput("http://exchange.local/") + state.url.onInput("http://exchange.local/"); }, ], TestingContext, diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx b/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx @@ -143,7 +143,7 @@ export function VerifyView({ } e.preventDefault() }}> - {ex.href}</a></li> + {ex.href}</a></li> })} </ul> </section> @@ -159,8 +159,6 @@ export function ConfirmView({ }: State.Confirm): VNode { const { i18n } = useTranslationContext(); - const [accepted, setAccepted] = useState(false); - return ( <Fragment> <section> @@ -175,27 +173,27 @@ export function ConfirmView({ </div> </section> - <TermsOfService key="terms" exchangeUrl={url} onChange={setAccepted} /> - <footer> - <Button - key="cancel" - variant="contained" - color="secondary" - onClick={onCancel} - > - <i18n.Translate>Cancel</i18n.Translate> - </Button> - <Button - key="add" - variant="contained" - color="success" - disabled={!accepted} - onClick={onConfirm} - > - <i18n.Translate>Add exchange</i18n.Translate> - </Button> - </footer> + <TermsOfService key="terms" exchangeUrl={url} > + <footer> + <Button + key="cancel" + variant="contained" + color="secondary" + onClick={onCancel} + > + <i18n.Translate>Cancel</i18n.Translate> + </Button> + <Button + key="add" + variant="contained" + color="success" + onClick={onConfirm} + > + <i18n.Translate>Add exchange</i18n.Translate> + </Button> + </footer> + </TermsOfService> </Fragment> ); } diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx b/packages/taler-wallet-webextension/src/wallet/Application.tsx @@ -404,10 +404,8 @@ export function Application(): VNode { }) => ( <CallToActionTemplate title={i18n.str`Digital cash withdrawal`}> <WithdrawPageFromParams - onAmountChanged={async (e) => { - const page = `${Pages.ctaWithdrawManual({ - amount, - })}?talerUri=${encodeURIComponent(talerUri)}`; + onAmountChanged={async (newamount) => { + const page = `${Pages.ctaWithdrawManual({ amount: newamount })}?talerUri=${encodeURIComponent(talerUri)}`; redirectTo(page); }} talerExchangeWithdrawUri={talerUri} diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts @@ -36,6 +36,7 @@ import { useComponentState } from "./state.js"; const exchangeArs: ExchangeListItem = { currency: "ARS", exchangeBaseUrl: "http://", + scopeInfo: undefined, tosStatus: ExchangeTosStatus.Accepted, exchangeEntryStatus: ExchangeEntryStatus.Used, exchangeUpdateStatus: ExchangeUpdateStatus.Initial, diff --git a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx @@ -258,6 +258,20 @@ export function View({ </Button> </Grid> <Grid item> + <Button variant="contained" onClick={async () => { + api.background.call("toggleHeaderListener", true) + }}> + <i18n.Translate>enable header listener</i18n.Translate> + </Button> + </Grid> + <Grid item> + <Button variant="contained" onClick={async () => { + api.background.call("toggleHeaderListener", false) + }}> + <i18n.Translate>disable header listener</i18n.Translate> + </Button> + </Grid> + <Grid item> <Button variant="contained" onClick={async () => { diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx @@ -135,7 +135,9 @@ export function TosContentView({ <Button variant="outlined" onClick={onClose.onClick}> <i18n.Translate>Close</i18n.Translate> </Button> - <TermsOfService exchangeUrl={exchangeUrl} /> + <TermsOfService exchangeUrl={exchangeUrl} readOnly > + s + </TermsOfService> </div> ); } diff --git a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx @@ -39,7 +39,7 @@ export const TalerBank = tests.createExample(TestedComponent, { value: 10, fraction: 0, }, - exchangeBaseUrl: "https://exchange.demo.taler.net", + accounts: [] }); export const IBAN = tests.createExample(TestedComponent, { @@ -52,7 +52,7 @@ export const IBAN = tests.createExample(TestedComponent, { value: 10, fraction: 0, }, - exchangeBaseUrl: "https://exchange.demo.taler.net", + accounts: [] }); export const WithReceiverName = tests.createExample(TestedComponent, { @@ -65,7 +65,7 @@ export const WithReceiverName = tests.createExample(TestedComponent, { value: 10, fraction: 0, }, - exchangeBaseUrl: "https://exchange.demo.taler.net", + accounts: [] }); export const Bitcoin = tests.createExample(TestedComponent, { @@ -78,7 +78,7 @@ export const Bitcoin = tests.createExample(TestedComponent, { value: 0, fraction: 14000000, }, - exchangeBaseUrl: "https://exchange.demo.taler.net", + accounts: [] }); export const BitcoinRegTest = tests.createExample(TestedComponent, { @@ -91,7 +91,7 @@ export const BitcoinRegTest = tests.createExample(TestedComponent, { value: 0, fraction: 14000000, }, - exchangeBaseUrl: "https://exchange.demo.taler.net", + accounts: [] }); export const BitcoinTest = tests.createExample(TestedComponent, { reservePub: "0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00", @@ -103,5 +103,5 @@ export const BitcoinTest = tests.createExample(TestedComponent, { value: 0, fraction: 14000000, }, - exchangeBaseUrl: "https://exchange.demo.taler.net", + accounts: [] }); diff --git a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { AmountJson, PaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util"; +import { AmountJson, PaytoUri, WithdrawalExchangeAccountDetails, stringifyPaytoUri } from "@gnu-taler/taler-util"; import { Fragment, h, VNode } from "preact"; import { Amount } from "../components/Amount.js"; import { BankDetailsByPaytoType } from "../components/BankDetailsByPaytoType.js"; @@ -26,7 +26,7 @@ import { Button } from "../mui/Button.js"; export interface Props { reservePub: string; paytoURI: PaytoUri | undefined; - exchangeBaseUrl: string; + accounts: WithdrawalExchangeAccountDetails[]; amount: AmountJson; onCancel: () => Promise<void>; } @@ -35,7 +35,7 @@ export function ReserveCreated({ reservePub, paytoURI, onCancel, - exchangeBaseUrl, + accounts, amount, }: Props): VNode { const { i18n } = useTranslationContext(); @@ -47,17 +47,6 @@ export function ReserveCreated({ /> ); } - function TransferDetails(): VNode { - if (!paytoURI) return <Fragment />; - return ( - <BankDetailsByPaytoType - amount={amount} - exchangeBaseUrl={exchangeBaseUrl} - subject={reservePub} - /> - ); - } - return ( <Fragment> <section> @@ -71,7 +60,11 @@ export function ReserveCreated({ </i18n.Translate> </p> </section> - <TransferDetails /> + <BankDetailsByPaytoType + amount={amount} + accounts={accounts} + subject={reservePub} + /> <section> <p> <i18n.Translate> diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx @@ -21,6 +21,7 @@ import * as tests from "@gnu-taler/web-util/testing"; import { SettingsView as TestedComponent } from "./Settings.js"; +import { WalletCoreVersion } from "@gnu-taler/taler-util"; export default { title: "settings", @@ -38,12 +39,14 @@ const version = { hash: "d439c3e1bc743f2aa47de4457953dba6ecb0e20f", version: "0.9.0-dev.1", devMode: false, - }, + bankConversionApiRange: "0:0:0", + bankIntegrationApiRange: "0:0:0", + corebankApiRange: "0:0:0", + } satisfies WalletCoreVersion, webexVersion: { version: "0.9.0.13", hash: "d439c3e1bc743f2aa47de4457953dba6ecb0e20f", }, - }; export const AllOff = tests.createExample(TestedComponent, { diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx @@ -293,6 +293,12 @@ export const WithdrawPendingManual = tests.createExample( type: WithdrawalType.ManualTransfer, exchangePaytoUris: ["payto://iban/ES8877998399652238"], reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG", + exchangeCreditAccountDetails: [{ + paytoUri: "payto://IBAN/1231231231", + }, + { + paytoUri: "payto://IBAN/2342342342", + }], } as WithdrawalDetails, txState: { major: TransactionMajorState.Pending, diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx @@ -19,7 +19,6 @@ import { AmountJson, Amounts, AmountString, - Location, MerchantInfo, NotificationType, OrderShortInfo, @@ -28,7 +27,6 @@ import { stringifyPaytoUri, TalerErrorCode, TalerPreciseTimestamp, - TalerProtocolTimestamp, Transaction, TransactionAction, TransactionDeposit, @@ -39,7 +37,7 @@ import { TransactionType, TransactionWithdrawal, TranslatedString, - WithdrawalType, + WithdrawalType } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; @@ -47,13 +45,12 @@ import { styled } from "@linaria/react"; import { isPast } from "date-fns"; import { ComponentChildren, Fragment, h, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; -import emptyImg from "../../static/img/empty.png"; import { Amount } from "../components/Amount.js"; import { BankDetailsByPaytoType } from "../components/BankDetailsByPaytoType.js"; import { AlertView, ErrorAlertView } from "../components/CurrentAlerts.js"; import { EnabledBySettings } from "../components/EnabledBySettings.js"; import { Loading } from "../components/Loading.js"; -import { Kind, Part, PartCollapsible, PartPayto } from "../components/Part.js"; +import { Kind, Part, PartPayto } from "../components/Part.js"; import { QR } from "../components/QR.js"; import { ShowFullContractTermPopup } from "../components/ShowFullContractTermPopup.js"; import { @@ -61,13 +58,11 @@ import { ErrorBox, InfoBox, Link, - ListOfProducts, Overlay, - Row, SmallLightText, SubTitle, SvgIcon, - WarningBox, + WarningBox } from "../components/styled/index.js"; import { Time } from "../components/Time.js"; import { alertFromError, useAlertContext } from "../context/alert.js"; @@ -77,12 +72,8 @@ import { useSettings } from "../hooks/useSettings.js"; import { Button } from "../mui/Button.js"; import { SafeHandler } from "../mui/handlers.js"; import { Pages } from "../NavigationBar.js"; -import { assertUnreachable } from "../utils/index.js"; import refreshIcon from "../svg/refresh_24px.inline.svg"; -import refreshIcon1 from "../svg/refresh_outlined_24px.inline.svg"; -import refreshIcon2 from "../svg/refresh_rounded_24px.inline.svg"; -import refreshIcon3 from "../svg/refresh_sharp_24px.inline.svg"; -import refreshIcon4 from "../svg/refresh_two_tone_24px.inline.svg"; +import { assertUnreachable } from "../utils/index.js"; interface Props { tid: string; @@ -444,6 +435,8 @@ export function TransactionView({ transaction.type === TransactionType.Withdrawal || transaction.type === TransactionType.InternalWithdrawal ) { + const conversion = transaction.withdrawalDetails.type === WithdrawalType.ManualTransfer ? + transaction.withdrawalDetails.exchangeCreditAccountDetails ?? [] : [] return ( <TransactionTemplate transaction={transaction} @@ -472,7 +465,7 @@ export function TransactionView({ //manual withdrawal <BankDetailsByPaytoType amount={raw} - exchangeBaseUrl={transaction.exchangeBaseUrl} + accounts={transaction.withdrawalDetails.exchangeCreditAccountDetails ?? []} subject={transaction.withdrawalDetails.reservePub} /> ) : ( @@ -973,12 +966,12 @@ export function TransactionView({ kind="neutral" /> {transaction.talerUri && ( - <Part - title={i18n.str`URI`} - text={<ShowQrWithCopy text={transaction.talerUri} />} - kind="neutral" - /> - )} + <Part + title={i18n.str`URI`} + text={<ShowQrWithCopy text={transaction.talerUri} />} + kind="neutral" + /> + )} <Part title={i18n.str`Details`} text={ @@ -1417,7 +1410,7 @@ export function TransferPickupDetails({ </PurchaseDetailsTable> ); } -export function WithdrawDetails({ amount }: { amount: AmountWithFee }): VNode { +export function WithdrawDetails({ conversion, amount }: { conversion?: AmountJson, amount: AmountWithFee }): VNode { const { i18n } = useTranslationContext(); const maxFrac = [amount.fee, amount.fee] @@ -1428,15 +1421,36 @@ export function WithdrawDetails({ amount }: { amount: AmountWithFee }): VNode { return ( <PurchaseDetailsTable> - <tr> - <td> - <i18n.Translate>Transfer</i18n.Translate> - </td> - <td> - <Amount value={amount.value} maxFracSize={amount.maxFrac} /> - </td> - </tr> - + {conversion ? + <Fragment> + <tr> + <td> + <i18n.Translate>Transfer</i18n.Translate> + </td> + <td> + <Amount value={conversion} maxFracSize={amount.maxFrac} /> + </td> + </tr> + {conversion.fraction === amount.value.fraction && conversion.value === amount.value.value ? undefined : + <tr> + <td> + <i18n.Translate>Converted</i18n.Translate> + </td> + <td> + <Amount value={amount.value} maxFracSize={amount.maxFrac} /> + </td> + </tr> + } + </Fragment> + : <tr> + <td> + <i18n.Translate>Transfer</i18n.Translate> + </td> + <td> + <Amount value={amount.value} maxFracSize={amount.maxFrac} /> + </td> + </tr> + } {Amounts.isNonZero(amount.fee) && ( <tr> <td> @@ -2007,7 +2021,7 @@ function ShowWithdrawalDetailForBankIntegrated({ {showDetails && ( <BankDetailsByPaytoType amount={raw} - exchangeBaseUrl={transaction.exchangeBaseUrl} + accounts={transaction.withdrawalDetails.exchangeCreditAccountDetails ?? []} subject={transaction.withdrawalDetails.reservePub} /> )} diff --git a/packages/taler-wallet-webextension/src/wxApi.ts b/packages/taler-wallet-webextension/src/wxApi.ts @@ -83,14 +83,14 @@ export interface BackgroundOperations { }; response: void; }; - // containsHeaderListener: { - // request: void; - // response: ExtendedPermissionsResponse; - // }; - // toggleHeaderListener: { - // request: boolean; - // response: ExtendedPermissionsResponse; - // }; + containsHeaderListener: { + request: void; + response: ExtendedPermissionsResponse; + }; + toggleHeaderListener: { + request: boolean; + response: ExtendedPermissionsResponse; + }; } export interface BackgroundApiClient { diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts @@ -53,7 +53,7 @@ import { import { MessageFromFrontend, MessageResponse } from "./platform/api.js"; import { platform } from "./platform/background.js"; import { ExtensionOperations } from "./taler-wallet-interaction-loader.js"; -import { BackgroundOperations } from "./wxApi.js"; +import { BackgroundOperations, ExtendedPermissionsResponse } from "./wxApi.js"; /** * Currently active wallet instance. Might be unloaded and @@ -142,12 +142,14 @@ const backendHandlers: BackendHandlerType = { resetDb, runGarbageCollector, setLoggingLevel, + containsHeaderListener, + toggleHeaderListener, }; -// async function containsHeaderListener(): Promise<ExtendedPermissionsResponse> { -// const result = await platform.containsTalerHeaderListener(); -// return { newValue: result }; -// } +async function containsHeaderListener(): Promise<ExtendedPermissionsResponse> { + const result = platform.containsTalerHeaderListener(); + return { newValue: result }; +} async function setLoggingLevel({ tag, @@ -329,10 +331,12 @@ export async function wxMain(): Promise<void> { logger.trace("starting"); const afterWalletIsInitialized = reinitWallet(); + logger.trace("reload on new version"); platform.registerReloadOnNewVersion(); // Handlers for messages coming directly from the content // script on the page + logger.trace("listen all channels"); platform.listenToAllChannels(async (message) => { //wait until wallet is initialized await afterWalletIsInitialized; @@ -340,10 +344,12 @@ export async function wxMain(): Promise<void> { return result; }); + logger.trace("register all incoming connections"); platform.registerAllIncomingConnections(); + logger.trace("redirect if first start"); try { - await platform.registerOnInstalled(() => { + platform.registerOnInstalled(() => { platform.openWalletPage("/welcome"); }); } catch (e) { @@ -358,46 +364,57 @@ export async function wxMain(): Promise<void> { * which doesn't make sense, keeping it to make more tests */ - // if (await isHeaderListenerEnabled()) { - // if (await platform.getPermissionsApi().containsHostPermissions()) { - // try { - // platform.registerTalerHeaderListener(); - // } catch (e) { - // logger.error("could not register header listener", e); - // } - // } else { - // await platform.getPermissionsApi().requestHostPermissions() - // } - // } + logger.trace("check taler header listener"); + const enabled = platform.containsTalerHeaderListener() + if (!enabled) { + logger.info("header listener on") + const perm = await platform.getPermissionsApi().containsHostPermissions() + if (perm) { + logger.info("header listener allowed") + try { + platform.registerTalerHeaderListener(); + } catch (e) { + logger.error("could not register header listener", e); + } + } else { + logger.info("header listener requested") + await platform.getPermissionsApi().requestHostPermissions() + } + } // On platforms that support it, also listen to external // modification of permissions. - // platform.getPermissionsApi().addPermissionsListener((perm, lastError) => { - // logger.info(`permission added: ${perm}`,) - // if (lastError) { - // logger.error( - // `there was a problem trying to get permission ${perm}`, - // lastError, - // ); - // return; - // } - // platform.registerTalerHeaderListener(); - // }); + platform.getPermissionsApi().addPermissionsListener((perm, lastError) => { + logger.info(`permission added: ${perm}`,) + if (lastError) { + logger.error( + `there was a problem trying to get permission ${perm}`, + lastError, + ); + return; + } + platform.registerTalerHeaderListener(); + }); // } } -// async function toggleHeaderListener( -// newVal: boolean, -// ): Promise<ExtendedPermissionsResponse> { -// logger.trace("new extended permissions value", newVal); -// if (newVal) { -// platform.registerTalerHeaderListener(); -// return { newValue: true }; -// } +async function toggleHeaderListener( + newVal: boolean, +): Promise<ExtendedPermissionsResponse> { + logger.trace("new extended permissions value", newVal); + if (newVal) { + try { + platform.registerTalerHeaderListener(); + return { newValue: true }; + } catch (e) { + logger.error("FAIL to toggle",e) + } + return { newValue: false } + } -// const rem = await platform.getPermissionsApi().removeHostPermissions(); -// logger.trace("permissions removed:", rem); -// return { newValue: false }; -// } + const rem = await platform.getPermissionsApi().removeHostPermissions(); + logger.trace("permissions removed:", rem); + return { newValue: false }; +} diff --git a/packages/taler-wallet-webextension/tsconfig.json b/packages/taler-wallet-webextension/tsconfig.json @@ -7,7 +7,7 @@ "jsxFragmentFactory": "Fragment", // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-0.html#custom-jsx-factories "moduleResolution": "Node16", "module": "Node16", - "target": "ES6", + "target": "ES2020", "skipLibCheck": true, "preserveSymlinks": true, "noImplicitAny": true, diff --git a/packages/web-util/package.json b/packages/web-util/package.json @@ -36,28 +36,28 @@ "@babel/preset-typescript": "^7.21.5", "@gnu-taler/taler-util": "workspace:*", "@heroicons/react": "^2.0.17", - "date-fns": "2.29.3", - "@linaria/babel-preset": "4.4.5", - "@linaria/core": "4.2.10", - "@linaria/esbuild": "4.2.11", - "@linaria/react": "4.3.8", + "@linaria/babel-preset": "5.0.4", + "@linaria/core": "5.0.2", + "@linaria/esbuild": "5.0.4", + "@linaria/react": "5.0.3", "@types/express": "^4.17.14", "@types/node": "^18.11.17", "@types/web": "^0.0.82", "@types/ws": "^8.5.3", "autoprefixer": "^10.4.14", "chokidar": "^3.5.3", - "esbuild": "^0.17.7", + "date-fns": "2.29.3", + "esbuild": "^0.19.9", "express": "^4.18.2", "postcss": "^8.4.23", "postcss-load-config": "^4.0.1", "preact": "10.11.3", "preact-render-to-string": "^5.2.6", - "prettier": "^2.8.8", + "prettier": "^3.1.1", "sass": "1.56.1", "swr": "2.0.3", - "tslib": "^2.5.3", - "typescript": "^5.2.2", + "tslib": "^2.6.2", + "typescript": "^5.3.3", "ws": "7.4.5" }, "dependencies": { @@ -66,4 +66,4 @@ "@types/chrome": "0.0.197", "tailwindcss": "^3.3.2" } -} -\ No newline at end of file +} diff --git a/packages/web-util/src/components/CopyButton.tsx b/packages/web-util/src/components/CopyButton.tsx @@ -20,8 +20,13 @@ export function CopiedIcon(): VNode { export function CopyButton({ class: clazz, getContent }: { class: string, getContent: () => string }): VNode { const [copied, setCopied] = useState(false); function copyText(): void { - navigator.clipboard.writeText(getContent() || ""); - setCopied(true); + if (!navigator.clipboard && !window.isSecureContext) { + alert('clipboard is not available on insecure context (http)') + } + if (navigator.clipboard) { + navigator.clipboard.writeText(getContent() || ""); + setCopied(true); + } } useEffect(() => { if (copied) { diff --git a/packages/web-util/src/components/Footer.tsx b/packages/web-util/src/components/Footer.tsx @@ -1,8 +1,12 @@ import { useTranslationContext } from "../index.browser.js"; import { h } from "preact"; -export function Footer({ testingUrl, VERSION, GIT_HASH }: { VERSION?: string, GIT_HASH?: string, testingUrl?: string }) { +export function Footer({ testingUrlKey, VERSION, GIT_HASH }: { VERSION?: string, GIT_HASH?: string, testingUrlKey?: string }) { const { i18n } = useTranslationContext() + + const testingUrl = (testingUrlKey && typeof localStorage !== "undefined") && localStorage.getItem(testingUrlKey) ? + localStorage.getItem(testingUrlKey) ?? undefined : + undefined const versionText = VERSION ? GIT_HASH ? <a href={`https://git.taler.net/wallet-core.git/tree/?id=${GIT_HASH}`} target="_blank" rel="noreferrer noopener"> @@ -23,7 +27,7 @@ export function Footer({ testingUrl, VERSION, GIT_HASH }: { VERSION?: string, GI <p class="text-xs leading-5 text-gray-400"> Copyright © 2014—2023 Taler Systems SA. {versionText}{" "} </p> - {testingUrl && + {testingUrlKey && testingUrl && <p class="text-xs leading-5 text-gray-300"> Testing with {testingUrl}{" "} @@ -31,7 +35,7 @@ export function Footer({ testingUrl, VERSION, GIT_HASH }: { VERSION?: string, GI href="" onClick={(e) => { e.preventDefault(); - localStorage.removeItem("bank-base-url"); + localStorage.removeItem(testingUrlKey); window.location.reload(); }} > diff --git a/packages/web-util/src/utils/http-impl.browser.ts b/packages/web-util/src/utils/http-impl.browser.ts @@ -140,22 +140,24 @@ export class BrowserHttpLib implements HttpRequestLibrary { const td = new TextDecoder(); return td.decode(myRequest.response); }; + let responseJson: unknown = undefined; const makeJson = async (): Promise<any> => { - let responseJson; - try { - const td = new TextDecoder(); - const responseString = td.decode(myRequest.response); - responseJson = JSON.parse(responseString); - } catch (e) { - throw TalerError.fromDetail( - TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, - { - requestUrl, - requestMethod, - httpStatusCode: myRequest.status, - }, - "Invalid JSON from HTTP response", - ); + if (responseJson === undefined) { + try { + const td = new TextDecoder(); + const responseString = td.decode(myRequest.response); + responseJson = JSON.parse(responseString); + } catch (e) { + throw TalerError.fromDetail( + TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, + { + requestUrl, + requestMethod, + httpStatusCode: myRequest.status, + }, + "Invalid JSON from HTTP response", + ); + } } if (responseJson === null || typeof responseJson !== "object") { throw TalerError.fromDetail( diff --git a/packages/web-util/src/utils/http-impl.sw.ts b/packages/web-util/src/utils/http-impl.sw.ts @@ -176,20 +176,23 @@ function makeJsonHandler( requestUrl: string, requestMethod: string, ) { + let responseJson: unknown = undefined; return async function getJsonFromResponse(): Promise<any> { - let responseJson; - try { - responseJson = await response.json(); - } catch (e) { - throw TalerError.fromDetail( - TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, - { - requestUrl, - requestMethod, - httpStatusCode: response.status, - }, - "Invalid JSON from HTTP response", - ); + if (responseJson === undefined) { + try { + responseJson = await response.json(); + } catch (e) { + const message = e instanceof Error ? `Invalid JSON from HTTP response: ${e.message}` : "Invalid JSON from HTTP response" + throw TalerError.fromDetail( + TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, + { + requestUrl, + requestMethod, + httpStatusCode: response.status, + }, + message, + ); + } } if (responseJson === null || typeof responseJson !== "object") { throw TalerError.fromDetail( @@ -199,7 +202,7 @@ function makeJsonHandler( requestMethod, httpStatusCode: response.status, }, - "Invalid JSON from HTTP response", + "Invalid JSON from HTTP response: null or not object", ); } return responseJson; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml @@ -18,17 +18,17 @@ importers: specifier: ^3.0.0-beta.15 version: 3.0.0-beta.23 esbuild: - specifier: ^0.17.7 - version: 0.17.7 + specifier: ^0.19.9 + version: 0.19.9 prettier: - specifier: ^2.8.8 - version: 2.8.8 + specifier: ^3.1.1 + version: 3.1.1 typedoc: - specifier: ^0.25.1 - version: 0.25.1(typescript@5.2.2) + specifier: ^0.25.4 + version: 0.25.4(typescript@5.3.3) typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: ^5.3.3 + version: 5.3.3 packages/aml-backoffice-ui: dependencies: @@ -85,11 +85,11 @@ importers: specifier: ^4.3.6 version: 4.3.6 esbuild: - specifier: ^0.17.7 - version: 0.17.19 + specifier: ^0.19.9 + version: 0.19.9 eslint-config-preact: specifier: ^1.2.0 - version: 1.3.0(@typescript-eslint/eslint-plugin@5.41.0)(eslint@8.48.0)(typescript@5.2.2) + version: 1.3.0(@typescript-eslint/eslint-plugin@5.41.0)(eslint@8.55.0)(typescript@5.3.3) mocha: specifier: ^9.2.0 version: 9.2.2 @@ -106,8 +106,8 @@ importers: specifier: ^3.3.2 version: 3.3.2 typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.3 + version: 5.3.3 packages/anastasis-cli: dependencies: @@ -118,21 +118,21 @@ importers: specifier: workspace:* version: link:../taler-util tslib: - specifier: ^2.5.3 - version: 2.5.3 + specifier: ^2.6.2 + version: 2.6.2 devDependencies: '@types/node': specifier: ^18.11.17 version: 18.11.17 prettier: - specifier: ^2.8.8 - version: 2.8.8 + specifier: ^3.1.1 + version: 3.1.1 typedoc: - specifier: ^0.25.1 - version: 0.25.1(typescript@5.2.2) + specifier: ^0.25.4 + version: 0.25.4(typescript@5.3.3) typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: ^5.3.3 + version: 5.3.3 packages/anastasis-core: dependencies: @@ -140,18 +140,18 @@ importers: specifier: workspace:* version: link:../taler-util fflate: - specifier: ^0.7.4 - version: 0.7.4 + specifier: ^0.8.1 + version: 0.8.1 tslib: - specifier: ^2.5.3 - version: 2.5.3 + specifier: ^2.6.2 + version: 2.6.2 devDependencies: ava: - specifier: ^4.3.3 - version: 4.3.3(@ava/typescript@4.0.0) + specifier: ^6.0.1 + version: 6.0.1(@ava/typescript@4.1.0) typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: ^5.3.3 + version: 5.3.3 packages/anastasis-webui: dependencies: @@ -211,8 +211,8 @@ importers: specifier: 1.56.1 version: 1.56.1 typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: ^5.3.3 + version: 5.3.3 packages/challenger-ui: devDependencies: @@ -232,8 +232,8 @@ importers: specifier: ^10.4.14 version: 10.4.14(postcss@8.4.23) esbuild: - specifier: ^0.17.7 - version: 0.17.19 + specifier: ^0.19.9 + version: 0.19.9 po2json: specifier: ^0.4.5 version: 0.4.5 @@ -303,13 +303,13 @@ importers: version: 18.11.17 '@typescript-eslint/eslint-plugin': specifier: ^5.41.0 - version: 5.41.0(@typescript-eslint/parser@5.41.0)(eslint@8.48.0)(typescript@5.2.2) + version: 5.41.0(@typescript-eslint/parser@5.41.0)(eslint@8.55.0)(typescript@5.3.3) '@typescript-eslint/parser': specifier: ^5.41.0 - version: 5.41.0(eslint@8.48.0)(typescript@5.2.2) + version: 5.41.0(eslint@8.55.0)(typescript@5.3.3) autoprefixer: specifier: ^10.4.14 - version: 10.4.14(postcss@8.4.23) + version: 10.4.14(postcss@8.4.32) bulma: specifier: ^0.9.4 version: 0.9.4 @@ -323,11 +323,11 @@ importers: specifier: ^4.3.6 version: 4.3.6 esbuild: - specifier: ^0.17.7 - version: 0.17.7 + specifier: ^0.19.9 + version: 0.19.9 eslint-config-preact: specifier: ^1.2.0 - version: 1.3.0(@typescript-eslint/eslint-plugin@5.41.0)(eslint@8.48.0)(typescript@5.2.2) + version: 1.3.0(@typescript-eslint/eslint-plugin@5.41.0)(eslint@8.55.0)(typescript@5.3.3) mocha: specifier: ^9.2.0 version: 9.2.2 @@ -344,34 +344,34 @@ importers: specifier: ^3.3.2 version: 3.3.2 typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.3 + version: 5.3.3 packages/idb-bridge: dependencies: tslib: - specifier: ^2.6.0 - version: 2.6.0 + specifier: ^2.6.2 + version: 2.6.2 optionalDependencies: better-sqlite3: - specifier: ^8.4.0 - version: 8.4.0 + specifier: ^9.2.2 + version: 9.2.2 devDependencies: '@types/better-sqlite3': - specifier: ^7.6.4 - version: 7.6.4 + specifier: ^7.6.8 + version: 7.6.8 '@types/node': specifier: ^20.4.1 version: 20.4.1 ava: - specifier: ^5.3.1 - version: 5.3.1 + specifier: ^6.0.1 + version: 6.0.1(@ava/typescript@4.1.0) prettier: - specifier: ^2.8.8 - version: 2.8.8 + specifier: ^3.1.1 + version: 3.1.1 typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: ^5.3.3 + version: 5.3.3 packages/merchant-backend-ui: dependencies: @@ -405,7 +405,7 @@ importers: version: 3.0.0-beta.22 '@linaria/webpack-loader': specifier: 3.0.0-beta.22 - version: 3.0.0-beta.22(webpack@4.46.0) + version: 3.0.0-beta.22(webpack@4.47.0) '@types/mocha': specifier: ^8.2.2 version: 8.2.3 @@ -414,22 +414,22 @@ importers: version: 4.2.1 '@typescript-eslint/eslint-plugin': specifier: ^4.22.0 - version: 4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.2.2) + version: 4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.3.3) '@typescript-eslint/parser': specifier: ^4.22.0 - version: 4.33.0(eslint@7.32.0)(typescript@5.2.2) + version: 4.33.0(eslint@7.32.0)(typescript@5.3.3) babel-loader: specifier: ^8.2.2 - version: 8.2.5(@babel/core@7.18.9)(webpack@4.46.0) + version: 8.2.5(@babel/core@7.18.9)(webpack@4.47.0) base64-inline-loader: specifier: ^1.1.1 - version: 1.1.1(webpack@4.46.0) + version: 1.1.1(webpack@4.47.0) eslint: specifier: ^7.25.0 version: 7.32.0 eslint-config-preact: specifier: ^1.1.4 - version: 1.3.0(@typescript-eslint/eslint-plugin@4.33.0)(eslint@7.32.0)(typescript@5.2.2) + version: 1.3.0(@typescript-eslint/eslint-plugin@4.33.0)(eslint@7.32.0)(typescript@5.3.3) eslint-plugin-header: specifier: ^3.1.1 version: 3.1.1(eslint@7.32.0) @@ -447,13 +447,13 @@ importers: version: 1.0.14 ts-node: specifier: ^10.9.1 - version: 10.9.1(@types/node@20.5.9)(typescript@5.2.2) + version: 10.9.1(@types/node@20.10.4)(typescript@5.3.3) tslib: - specifier: 2.5.3 - version: 2.5.3 + specifier: 2.6.2 + version: 2.6.2 typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.3 + version: 5.3.3 packages/merchant-backoffice-ui: dependencies: @@ -508,13 +508,13 @@ importers: version: 18.11.17 '@typescript-eslint/eslint-plugin': specifier: ^4.22.0 - version: 4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.2.2) + version: 4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.3.3) '@typescript-eslint/parser': specifier: ^4.22.0 - version: 4.33.0(eslint@7.32.0)(typescript@5.2.2) + version: 4.33.0(eslint@7.32.0)(typescript@5.3.3) base64-inline-loader: specifier: ^1.1.1 - version: 1.1.1(webpack@4.46.0) + version: 1.1.1(webpack@4.47.0) bulma: specifier: ^0.9.2 version: 0.9.4 @@ -547,7 +547,7 @@ importers: version: 7.32.0 eslint-config-preact: specifier: ^1.1.4 - version: 1.3.0(@typescript-eslint/eslint-plugin@4.33.0)(eslint@7.32.0)(typescript@5.2.2) + version: 1.3.0(@typescript-eslint/eslint-plugin@4.33.0)(eslint@7.32.0)(typescript@5.3.3) eslint-plugin-header: specifier: ^3.1.1 version: 3.1.1(eslint@7.32.0) @@ -559,7 +559,7 @@ importers: version: 0.0.10 html-webpack-skip-assets-plugin: specifier: ^1.0.1 - version: 1.0.3(html-webpack-plugin@5.5.3)(webpack@4.46.0) + version: 1.0.3(html-webpack-plugin@5.5.4)(webpack@4.47.0) inline-chunk-html-plugin: specifier: ^1.1.1 version: 1.1.1 @@ -576,11 +576,11 @@ importers: specifier: ^0.5.21 version: 0.5.21 typedoc: - specifier: ^0.25.1 - version: 0.25.1(typescript@5.2.2) + specifier: ^0.25.4 + version: 0.25.4(typescript@5.3.3) typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.3 + version: 5.3.3 packages/pogen: dependencies: @@ -588,15 +588,15 @@ importers: specifier: ^18.11.17 version: 18.11.17 glob: - specifier: ^7.2.0 - version: 7.2.3 + specifier: ^10.3.10 + version: 10.3.10 devDependencies: po2json: specifier: ^0.4.5 version: 0.4.5 typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: ^5.3.3 + version: 5.3.3 packages/taler-harness: dependencies: @@ -607,55 +607,55 @@ importers: specifier: workspace:* version: link:../taler-wallet-core tslib: - specifier: ^2.5.3 - version: 2.5.3 + specifier: ^2.6.2 + version: 2.6.2 devDependencies: '@types/node': specifier: ^18.11.17 version: 18.11.17 esbuild: - specifier: ^0.17.7 - version: 0.17.7 + specifier: ^0.19.9 + version: 0.19.9 prettier: - specifier: ^2.8.8 - version: 2.8.8 + specifier: ^3.1.1 + version: 3.1.1 typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: ^5.3.3 + version: 5.3.3 packages/taler-util: dependencies: big-integer: - specifier: ^1.6.51 - version: 1.6.51 + specifier: ^1.6.52 + version: 1.6.52 fflate: - specifier: ^0.7.4 - version: 0.7.4 + specifier: ^0.8.1 + version: 0.8.1 hash-wasm: - specifier: ^4.9.0 - version: 4.9.0 + specifier: ^4.11.0 + version: 4.11.0 jed: specifier: ^1.1.1 version: 1.1.1 tslib: - specifier: ^2.5.3 - version: 2.5.3 + specifier: ^2.6.2 + version: 2.6.2 devDependencies: '@types/node': specifier: ^18.11.17 version: 18.11.17 ava: - specifier: ^4.3.3 - version: 4.3.3(@ava/typescript@4.0.0) + specifier: ^6.0.1 + version: 6.0.1(@ava/typescript@4.1.0) esbuild: - specifier: ^0.17.7 - version: 0.17.7 + specifier: ^0.19.9 + version: 0.19.9 prettier: - specifier: ^2.8.8 - version: 2.8.8 + specifier: ^3.1.1 + version: 3.1.1 typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: ^5.3.3 + version: 5.3.3 packages/taler-wallet-cli: dependencies: @@ -666,21 +666,21 @@ importers: specifier: workspace:* version: link:../taler-wallet-core tslib: - specifier: ^2.5.3 - version: 2.5.3 + specifier: ^2.6.2 + version: 2.6.2 devDependencies: '@types/node': specifier: ^18.11.17 version: 18.11.17 prettier: - specifier: ^2.8.8 - version: 2.8.8 + specifier: ^3.1.1 + version: 3.1.1 typedoc: - specifier: ^0.25.1 - version: 0.25.1(typescript@5.2.2) + specifier: ^0.25.4 + version: 0.25.4(typescript@5.3.3) typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: ^5.3.3 + version: 5.3.3 packages/taler-wallet-core: dependencies: @@ -694,48 +694,48 @@ importers: specifier: ^18.11.17 version: 18.11.17 big-integer: - specifier: ^1.6.51 - version: 1.6.51 + specifier: ^1.6.52 + version: 1.6.52 fflate: - specifier: ^0.7.4 - version: 0.7.4 + specifier: ^0.8.1 + version: 0.8.1 tslib: - specifier: ^2.5.3 - version: 2.5.3 + specifier: ^2.6.2 + version: 2.6.2 devDependencies: '@ava/typescript': - specifier: ^4.0.0 - version: 4.0.0 + specifier: ^4.1.0 + version: 4.1.0 '@gnu-taler/pogen': specifier: workspace:* version: link:../pogen '@typescript-eslint/eslint-plugin': specifier: ^5.36.1 - version: 5.41.0(@typescript-eslint/parser@5.41.0)(eslint@8.26.0)(typescript@5.2.2) + version: 5.41.0(@typescript-eslint/parser@5.41.0)(eslint@8.26.0)(typescript@5.3.3) '@typescript-eslint/parser': specifier: ^5.36.1 - version: 5.41.0(eslint@8.26.0)(typescript@5.2.2) + version: 5.41.0(eslint@8.26.0)(typescript@5.3.3) ava: - specifier: ^4.3.3 - version: 4.3.3(@ava/typescript@4.0.0) + specifier: ^6.0.1 + version: 6.0.1(@ava/typescript@4.1.0) c8: - specifier: ^7.11.0 - version: 7.12.0 + specifier: ^8.0.1 + version: 8.0.1 eslint: specifier: ^8.8.0 version: 8.26.0 eslint-config-airbnb-typescript: - specifier: ^16.1.0 - version: 16.2.0(@typescript-eslint/eslint-plugin@5.41.0)(@typescript-eslint/parser@5.41.0)(eslint-plugin-import@2.26.0)(eslint@8.26.0) + specifier: ^17.1.0 + version: 17.1.0(@typescript-eslint/eslint-plugin@5.41.0)(@typescript-eslint/parser@5.41.0)(eslint-plugin-import@2.29.1)(eslint@8.26.0) eslint-plugin-import: - specifier: ^2.25.4 - version: 2.26.0(@typescript-eslint/parser@5.41.0)(eslint@8.26.0) + specifier: ^2.29.1 + version: 2.29.1(@typescript-eslint/parser@5.41.0)(eslint@8.26.0) eslint-plugin-jsx-a11y: - specifier: ^6.5.1 - version: 6.6.1(eslint@8.26.0) + specifier: ^6.8.0 + version: 6.8.0(eslint@8.26.0) eslint-plugin-react: - specifier: ^7.28.0 - version: 7.31.10(eslint@8.26.0) + specifier: ^7.33.2 + version: 7.33.2(eslint@8.26.0) eslint-plugin-react-hooks: specifier: ^4.3.0 version: 4.6.0(eslint@8.26.0) @@ -746,14 +746,14 @@ importers: specifier: ^0.4.5 version: 0.4.5 prettier: - specifier: ^2.8.8 - version: 2.8.8 + specifier: ^3.1.1 + version: 3.1.1 typedoc: - specifier: ^0.25.1 - version: 0.25.1(typescript@5.2.2) + specifier: ^0.25.4 + version: 0.25.4(typescript@5.3.3) typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: ^5.3.3 + version: 5.3.3 packages/taler-wallet-embedded: dependencies: @@ -770,18 +770,18 @@ importers: specifier: workspace:* version: link:../taler-wallet-core tslib: - specifier: ^2.5.3 - version: 2.5.3 + specifier: ^2.6.2 + version: 2.6.2 devDependencies: '@types/node': specifier: ^18.11.17 version: 18.11.17 esbuild: - specifier: ^0.17.7 - version: 0.17.7 + specifier: ^0.19.9 + version: 0.19.9 prettier: - specifier: ^2.8.8 - version: 2.8.8 + specifier: ^3.1.1 + version: 3.1.1 packages/taler-wallet-webextension: dependencies: @@ -810,15 +810,15 @@ importers: specifier: ^1.4.4 version: 1.4.4 tslib: - specifier: ^2.5.3 - version: 2.5.3 + specifier: ^2.6.2 + version: 2.6.2 devDependencies: '@babel/preset-react': specifier: ^7.22.3 - version: 7.22.3(@babel/core@7.18.9) + version: 7.22.3(@babel/core@7.23.6) '@babel/preset-typescript': specifier: 7.18.6 - version: 7.18.6(@babel/core@7.18.9) + version: 7.18.6(@babel/core@7.23.6) '@gnu-taler/pogen': specifier: workspace:* version: link:../pogen @@ -826,17 +826,20 @@ importers: specifier: workspace:* version: link:../web-util '@linaria/babel-preset': - specifier: ^4.4.5 - version: 4.4.5 + specifier: 5.0.4 + version: 5.0.4 '@linaria/core': - specifier: ^4.2.10 - version: 4.2.10 + specifier: 5.0.2 + version: 5.0.2 '@linaria/esbuild': - specifier: ^4.2.11 - version: 4.2.11(esbuild@0.17.19) + specifier: 5.0.4 + version: 5.0.4(esbuild@0.19.9) '@linaria/react': - specifier: ^4.3.8 - version: 4.3.8(react@18.2.0) + specifier: 5.0.3 + version: 5.0.3(react@18.2.0) + '@linaria/shaker': + specifier: 5.0.3 + version: 5.0.3 '@types/chai': specifier: ^4.3.0 version: 4.3.3 @@ -856,8 +859,8 @@ importers: specifier: ^4.3.6 version: 4.3.6 esbuild: - specifier: ^0.17.19 - version: 0.17.19 + specifier: ^0.19.9 + version: 0.19.9 mocha: specifier: ^9.2.0 version: 9.2.2 @@ -874,8 +877,8 @@ importers: specifier: ^5.1.19 version: 5.2.6(preact@10.11.3) typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.3.3 + version: 5.3.3 packages/web-util: dependencies: @@ -905,17 +908,17 @@ importers: specifier: ^2.0.17 version: 2.0.17(react@18.2.0) '@linaria/babel-preset': - specifier: 4.4.5 - version: 4.4.5 + specifier: 5.0.4 + version: 5.0.4 '@linaria/core': - specifier: 4.2.10 - version: 4.2.10 + specifier: 5.0.2 + version: 5.0.2 '@linaria/esbuild': - specifier: 4.2.11 - version: 4.2.11(esbuild@0.17.7) + specifier: 5.0.4 + version: 5.0.4(esbuild@0.19.9) '@linaria/react': - specifier: 4.3.8 - version: 4.3.8(react@18.2.0) + specifier: 5.0.3 + version: 5.0.3(react@18.2.0) '@types/express': specifier: ^4.17.14 version: 4.17.14 @@ -938,8 +941,8 @@ importers: specifier: 2.29.3 version: 2.29.3 esbuild: - specifier: ^0.17.7 - version: 0.17.7 + specifier: ^0.19.9 + version: 0.19.9 express: specifier: ^4.18.2 version: 4.18.2 @@ -956,8 +959,8 @@ importers: specifier: ^5.2.6 version: 5.2.6(preact@10.11.3) prettier: - specifier: ^2.8.8 - version: 2.8.8 + specifier: ^3.1.1 + version: 3.1.1 sass: specifier: 1.56.1 version: 1.56.1 @@ -965,11 +968,11 @@ importers: specifier: 2.0.3 version: 2.0.3(react@18.2.0) tslib: - specifier: ^2.5.3 - version: 2.5.3 + specifier: ^2.6.2 + version: 2.6.2 typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: ^5.3.3 + version: 5.3.3 ws: specifier: 7.4.5 version: 7.4.5 @@ -990,7 +993,15 @@ packages: engines: {node: '>=6.0.0'} dependencies: '@jridgewell/gen-mapping': 0.1.1 - '@jridgewell/trace-mapping': 0.3.17 + '@jridgewell/trace-mapping': 0.3.19 + + /@ampproject/remapping@2.2.1: + resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + dev: true /@apideck/better-ajv-errors@0.3.6(ajv@8.11.0): resolution: {integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==} @@ -1004,18 +1015,18 @@ packages: leven: 3.1.0 dev: true - /@ava/typescript@4.0.0: - resolution: {integrity: sha512-QFIPeqkEbdvn7Pob0wVeYpeZD0eXd8nDYdCl+knJVaIJrHdF2fXa58vFaig26cmYwnsEN0KRNTYJKbqW1B0lfg==} - engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} + /@ava/typescript@4.1.0: + resolution: {integrity: sha512-1iWZQ/nr9iflhLK9VN8H+1oDZqe93qxNnyYUz+jTzkYPAHc5fdZXBrqmNIgIfFhWYXK5OaQ5YtC7OmLeTNhVEg==} + engines: {node: ^14.19 || ^16.15 || ^18 || ^20} dependencies: escape-string-regexp: 5.0.0 - execa: 7.1.1 + execa: 7.2.0 dev: true /@babel/code-frame@7.12.11: resolution: {integrity: sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==} dependencies: - '@babel/highlight': 7.18.6 + '@babel/highlight': 7.23.4 dev: true /@babel/code-frame@7.18.6: @@ -1031,6 +1042,13 @@ packages: dependencies: '@babel/highlight': 7.18.6 + /@babel/code-frame@7.23.5: + resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.23.4 + chalk: 2.4.2 + /@babel/compat-data@7.19.4: resolution: {integrity: sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==} engines: {node: '>=6.9.0'} @@ -1040,8 +1058,8 @@ packages: resolution: {integrity: sha512-KYMqFYTaenzMK4yUtf4EW9wc4N9ef80FsbMtkwool5zpwl4YrT1SdWYSTRcT94KO4hannogdS+LxY7L+arP3gA==} engines: {node: '>=6.9.0'} - /@babel/compat-data@7.22.3: - resolution: {integrity: sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ==} + /@babel/compat-data@7.23.5: + resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} engines: {node: '>=6.9.0'} dev: true @@ -1095,20 +1113,66 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.0 - '@babel/code-frame': 7.21.4 - '@babel/generator': 7.22.3 - '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1) - '@babel/helper-module-transforms': 7.22.1 - '@babel/helpers': 7.22.3 - '@babel/parser': 7.22.4 - '@babel/template': 7.21.9 - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.5 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.1) + '@babel/helpers': 7.23.5 + '@babel/parser': 7.23.5 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.5 + '@babel/types': 7.23.5 convert-source-map: 1.9.0 debug: 4.3.4 gensync: 1.0.0-beta.2 json5: 2.2.3 - semver: 6.3.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/core@7.23.5: + resolution: {integrity: sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.0 + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.5 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5) + '@babel/helpers': 7.23.5 + '@babel/parser': 7.23.5 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.5 + '@babel/types': 7.23.5 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/core@7.23.6: + resolution: {integrity: sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.6 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.6) + '@babel/helpers': 7.23.6 + '@babel/parser': 7.23.6 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.6 + '@babel/types': 7.23.6 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true @@ -1127,7 +1191,7 @@ packages: semver: 6.3.0 dev: true - /@babel/eslint-parser@7.19.1(@babel/core@7.18.9)(eslint@8.48.0): + /@babel/eslint-parser@7.19.1(@babel/core@7.18.9)(eslint@8.55.0): resolution: {integrity: sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} peerDependencies: @@ -1136,7 +1200,7 @@ packages: dependencies: '@babel/core': 7.18.9 '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 - eslint: 8.48.0 + eslint: 8.55.0 eslint-visitor-keys: 2.1.0 semver: 6.3.0 dev: true @@ -1154,33 +1218,52 @@ packages: resolution: {integrity: sha512-SrKK/sRv8GesIW1bDagf9cCG38IOMYZusoe1dfg0D8aiUe3Amvoj1QtjTPAWcfrZFvIwlleLb0gxzQidL9w14w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.5 - '@jridgewell/gen-mapping': 0.3.2 - '@jridgewell/trace-mapping': 0.3.17 + '@babel/types': 7.23.5 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.19 jsesc: 2.5.2 /@babel/generator@7.22.3: resolution: {integrity: sha512-C17MW4wlk//ES/CJDL51kPNwl+qiBQyN7b9SKyVp11BLGFeSPoVaHrv+MNt8jwQFhQWowW88z1eeBx3pFz9v8A==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.5 '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.17 + '@jridgewell/trace-mapping': 0.3.19 jsesc: 2.5.2 + dev: true - /@babel/helper-annotate-as-pure@7.18.6: - resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} + /@babel/generator@7.23.5: + resolution: {integrity: sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.5 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.19 + jsesc: 2.5.2 + + /@babel/generator@7.23.6: + resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.6 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + jsesc: 2.5.2 dev: true - /@babel/helper-builder-binary-assignment-operator-visitor@7.18.9: - resolution: {integrity: sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==} + /@babel/helper-annotate-as-pure@7.22.5: + resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-explode-assignable-expression': 7.18.6 - '@babel/types': 7.22.4 + '@babel/types': 7.23.5 + dev: true + + /@babel/helper-builder-binary-assignment-operator-visitor@7.22.15: + resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 dev: true /@babel/helper-compilation-targets@7.18.9(@babel/core@7.13.16): @@ -1221,218 +1304,192 @@ packages: semver: 6.3.0 dev: true - /@babel/helper-compilation-targets@7.21.5(@babel/core@7.18.9): - resolution: {integrity: sha512-1RkbFGUKex4lvsB9yhIfWltJM5cZKUftB2eNajaDv3dCMEp49iBG0K14uH8NnX9IPux2+mK7JGEOB0jn48/J6w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/compat-data': 7.21.7 - '@babel/core': 7.18.9 - '@babel/helper-validator-option': 7.21.0 - browserslist: 4.21.5 - lru-cache: 5.1.1 - semver: 6.3.0 - dev: true - /@babel/helper-compilation-targets@7.21.5(@babel/core@7.22.1): resolution: {integrity: sha512-1RkbFGUKex4lvsB9yhIfWltJM5cZKUftB2eNajaDv3dCMEp49iBG0K14uH8NnX9IPux2+mK7JGEOB0jn48/J6w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.21.7 + '@babel/compat-data': 7.23.5 '@babel/core': 7.22.1 - '@babel/helper-validator-option': 7.21.0 - browserslist: 4.21.5 + '@babel/helper-validator-option': 7.23.5 + browserslist: 4.22.1 lru-cache: 5.1.1 - semver: 6.3.0 + semver: 6.3.1 dev: true - /@babel/helper-compilation-targets@7.22.1(@babel/core@7.18.9): - resolution: {integrity: sha512-Rqx13UM3yVB5q0D/KwQ8+SPfX/+Rnsy1Lw1k/UwOC4KC6qrzIQoY3lYnBu5EHKBlEHHcj0M0W8ltPSkD8rqfsQ==} + /@babel/helper-compilation-targets@7.22.15: + resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.22.3 - '@babel/core': 7.18.9 - '@babel/helper-validator-option': 7.21.0 - browserslist: 4.21.5 + '@babel/compat-data': 7.23.5 + '@babel/helper-validator-option': 7.23.5 + browserslist: 4.22.1 lru-cache: 5.1.1 - semver: 6.3.0 + semver: 6.3.1 dev: true - /@babel/helper-compilation-targets@7.22.1(@babel/core@7.22.1): - resolution: {integrity: sha512-Rqx13UM3yVB5q0D/KwQ8+SPfX/+Rnsy1Lw1k/UwOC4KC6qrzIQoY3lYnBu5EHKBlEHHcj0M0W8ltPSkD8rqfsQ==} + /@babel/helper-compilation-targets@7.23.6: + resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.22.3 - '@babel/core': 7.22.1 - '@babel/helper-validator-option': 7.21.0 - browserslist: 4.21.5 + '@babel/compat-data': 7.23.5 + '@babel/helper-validator-option': 7.23.5 + browserslist: 4.22.2 lru-cache: 5.1.1 - semver: 6.3.0 + semver: 6.3.1 dev: true - /@babel/helper-create-class-features-plugin@7.20.12(@babel/core@7.18.9): - resolution: {integrity: sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==} + /@babel/helper-create-class-features-plugin@7.23.5(@babel/core@7.18.9): + resolution: {integrity: sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.19.0 - '@babel/helper-member-expression-to-functions': 7.20.7 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/helper-replace-supers': 7.20.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/helper-split-export-declaration': 7.18.6 - transitivePeerDependencies: - - supports-color + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.18.9) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + semver: 6.3.1 dev: true - /@babel/helper-create-class-features-plugin@7.20.12(@babel/core@7.22.1): - resolution: {integrity: sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==} + /@babel/helper-create-class-features-plugin@7.23.5(@babel/core@7.22.1): + resolution: {integrity: sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.19.0 - '@babel/helper-member-expression-to-functions': 7.20.7 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/helper-replace-supers': 7.20.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/helper-split-export-declaration': 7.18.6 - transitivePeerDependencies: - - supports-color + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.22.1) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + semver: 6.3.1 dev: true - /@babel/helper-create-class-features-plugin@7.22.1(@babel/core@7.18.9): - resolution: {integrity: sha512-SowrZ9BWzYFgzUMwUmowbPSGu6CXL5MSuuCkG3bejahSpSymioPmuLdhPxNOc9MjuNGjy7M/HaXvJ8G82Lywlw==} + /@babel/helper-create-class-features-plugin@7.23.5(@babel/core@7.23.5): + resolution: {integrity: sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-function-name': 7.21.0 - '@babel/helper-member-expression-to-functions': 7.22.3 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/helper-replace-supers': 7.22.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/helper-split-export-declaration': 7.18.6 - semver: 6.3.0 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.5) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + semver: 6.3.1 dev: true - /@babel/helper-create-class-features-plugin@7.22.1(@babel/core@7.22.1): - resolution: {integrity: sha512-SowrZ9BWzYFgzUMwUmowbPSGu6CXL5MSuuCkG3bejahSpSymioPmuLdhPxNOc9MjuNGjy7M/HaXvJ8G82Lywlw==} + /@babel/helper-create-class-features-plugin@7.23.5(@babel/core@7.23.6): + resolution: {integrity: sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-function-name': 7.21.0 - '@babel/helper-member-expression-to-functions': 7.22.3 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/helper-replace-supers': 7.22.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/helper-split-export-declaration': 7.18.6 - semver: 6.3.0 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.6 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.6) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + semver: 6.3.1 dev: true - /@babel/helper-create-regexp-features-plugin@7.19.0(@babel/core@7.18.9): - resolution: {integrity: sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==} + /@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.18.9): + resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-annotate-as-pure': 7.18.6 - regexpu-core: 5.2.1 + '@babel/helper-annotate-as-pure': 7.22.5 + regexpu-core: 5.3.2 + semver: 6.3.1 dev: true - /@babel/helper-create-regexp-features-plugin@7.19.0(@babel/core@7.22.1): - resolution: {integrity: sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==} + /@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.22.1): + resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-annotate-as-pure': 7.18.6 - regexpu-core: 5.2.1 + '@babel/helper-annotate-as-pure': 7.22.5 + regexpu-core: 5.3.2 + semver: 6.3.1 dev: true - /@babel/helper-create-regexp-features-plugin@7.22.1(@babel/core@7.22.1): - resolution: {integrity: sha512-WWjdnfR3LPIe+0EY8td7WmjhytxXtjKAEpnAxun/hkNiyOaPlvGK+NZaBFIdi9ndYV3Gav7BpFvtUwnaJlwi1w==} + /@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.23.5): + resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-annotate-as-pure': 7.18.6 + '@babel/core': 7.23.5 + '@babel/helper-annotate-as-pure': 7.22.5 regexpu-core: 5.3.2 - semver: 6.3.0 + semver: 6.3.1 dev: true - /@babel/helper-define-polyfill-provider@0.3.3(@babel/core@7.18.9): + /@babel/helper-define-polyfill-provider@0.3.3(@babel/core@7.22.1): resolution: {integrity: sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==} peerDependencies: '@babel/core': ^7.4.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.18.9) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.22.1 + '@babel/helper-compilation-targets': 7.18.9(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 debug: 4.3.4 lodash.debounce: 4.0.8 resolve: 1.22.2 - semver: 6.3.0 + semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /@babel/helper-define-polyfill-provider@0.3.3(@babel/core@7.22.1): - resolution: {integrity: sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==} + /@babel/helper-define-polyfill-provider@0.4.3(@babel/core@7.18.9): + resolution: {integrity: sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==} peerDependencies: - '@babel/core': ^7.4.0-0 + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.18.9 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 debug: 4.3.4 lodash.debounce: 4.0.8 resolve: 1.22.2 - semver: 6.3.0 transitivePeerDependencies: - supports-color dev: true - /@babel/helper-define-polyfill-provider@0.4.0(@babel/core@7.22.1): - resolution: {integrity: sha512-RnanLx5ETe6aybRi1cO/edaRH+bNYWaryCEmjDDYyNr4wnSzyOp8T0dWipmqVHKEY3AbVKUom50AKSlj1zmKbg==} + /@babel/helper-define-polyfill-provider@0.4.3(@babel/core@7.23.5): + resolution: {integrity: sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==} peerDependencies: - '@babel/core': ^7.4.0-0 + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 debug: 4.3.4 lodash.debounce: 4.0.8 resolve: 1.22.2 - semver: 6.3.0 transitivePeerDependencies: - supports-color dev: true @@ -1442,71 +1499,64 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/helper-environment-visitor@7.22.1: - resolution: {integrity: sha512-Z2tgopurB/kTbidvzeBrc2To3PUP/9i5MUe+fU6QJCQDyPwSH2oRapkLw3KGECDYSjhQZCNxEvNvZlLw8JjGwA==} - engines: {node: '>=6.9.0'} - - /@babel/helper-explode-assignable-expression@7.18.6: - resolution: {integrity: sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==} + /@babel/helper-environment-visitor@7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.22.4 - dev: true /@babel/helper-function-name@7.19.0: resolution: {integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.18.10 - '@babel/types': 7.22.4 + '@babel/template': 7.22.15 + '@babel/types': 7.23.5 dev: true - /@babel/helper-function-name@7.21.0: - resolution: {integrity: sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==} + /@babel/helper-function-name@7.23.0: + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.21.9 - '@babel/types': 7.22.4 + '@babel/template': 7.22.15 + '@babel/types': 7.23.5 /@babel/helper-hoist-variables@7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 - - /@babel/helper-member-expression-to-functions@7.18.9: - resolution: {integrity: sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.5 dev: true - /@babel/helper-member-expression-to-functions@7.20.7: - resolution: {integrity: sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==} + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 - dev: true + '@babel/types': 7.23.5 - /@babel/helper-member-expression-to-functions@7.22.3: - resolution: {integrity: sha512-Gl7sK04b/2WOb6OPVeNy9eFKeD3L6++CzL3ykPOWqTn08xgYYK0wz4TUh2feIImDXxcVW3/9WQ1NMKY66/jfZA==} + /@babel/helper-member-expression-to-functions@7.23.0: + resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.5 dev: true /@babel/helper-module-imports@7.18.6: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.5 dev: true /@babel/helper-module-imports@7.21.4: resolution: {integrity: sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.5 + dev: true + + /@babel/helper-module-imports@7.22.15: + resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 /@babel/helper-module-transforms@7.19.6: resolution: {integrity: sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==} @@ -1528,38 +1578,78 @@ packages: resolution: {integrity: sha512-bI2Z9zBGY2q5yMHoBvJ2a9iX3ZOAzJPm7Q8Yz6YeoUjU/Cvhmi2G4QyTNyPBqqXSgTjUxRg3L0xV45HvkNWWBw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-module-imports': 7.21.4 - '@babel/helper-simple-access': 7.21.5 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/helper-validator-identifier': 7.19.1 - '@babel/template': 7.21.9 - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.5 + '@babel/types': 7.23.5 transitivePeerDependencies: - supports-color - /@babel/helper-module-transforms@7.22.1: - resolution: {integrity: sha512-dxAe9E7ySDGbQdCVOY/4+UcD8M9ZFqZcZhSPsPacvCG4M+9lwtDDQfI2EoaSvmf7W/8yCBkGU0m7Pvt1ru3UZw==} + /@babel/helper-module-transforms@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 dependencies: - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-module-imports': 7.21.4 - '@babel/helper-simple-access': 7.21.5 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/helper-validator-identifier': 7.19.1 - '@babel/template': 7.21.9 - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.18.9 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 dev: true - /@babel/helper-optimise-call-expression@7.18.6: - resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==} + /@babel/helper-module-transforms@7.23.3(@babel/core@7.22.1): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 dependencies: - '@babel/types': 7.22.4 + '@babel/core': 7.22.1 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + + /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + + /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.6): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.6 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + + /@babel/helper-optimise-call-expression@7.22.5: + resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 dev: true /@babel/helper-plugin-utils@7.19.0: @@ -1572,122 +1662,145 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/helper-remap-async-to-generator@7.18.9(@babel/core@7.18.9): - resolution: {integrity: sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==} + /@babel/helper-plugin-utils@7.22.5: + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.18.9): + resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-wrap-function': 7.19.0 - '@babel/types': 7.22.4 - transitivePeerDependencies: - - supports-color + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-wrap-function': 7.22.20 dev: true - /@babel/helper-remap-async-to-generator@7.18.9(@babel/core@7.22.1): - resolution: {integrity: sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==} + /@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.22.1): + resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-wrap-function': 7.19.0 - '@babel/types': 7.22.4 - transitivePeerDependencies: - - supports-color + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-wrap-function': 7.22.20 dev: true - /@babel/helper-replace-supers@7.19.1: - resolution: {integrity: sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==} + /@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.23.5): + resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 dependencies: - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-member-expression-to-functions': 7.18.9 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-wrap-function': 7.22.20 dev: true - /@babel/helper-replace-supers@7.20.7: - resolution: {integrity: sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==} + /@babel/helper-replace-supers@7.22.20(@babel/core@7.18.9): + resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 dependencies: - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-member-expression-to-functions': 7.20.7 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/template': 7.21.9 - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.18.9 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 dev: true - /@babel/helper-replace-supers@7.22.1: - resolution: {integrity: sha512-ut4qrkE4AuSfrwHSps51ekR1ZY/ygrP1tp0WFm8oVq6nzc/hvfV/22JylndIbsf2U2M9LOMwiSddr6y+78j+OQ==} + /@babel/helper-replace-supers@7.22.20(@babel/core@7.22.1): + resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 dependencies: - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-member-expression-to-functions': 7.22.3 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/template': 7.21.9 - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.22.1 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 dev: true - /@babel/helper-simple-access@7.19.4: - resolution: {integrity: sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==} + /@babel/helper-replace-supers@7.22.20(@babel/core@7.23.5): + resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 dependencies: - '@babel/types': 7.22.4 + '@babel/core': 7.23.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 dev: true - /@babel/helper-simple-access@7.21.5: - resolution: {integrity: sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==} + /@babel/helper-replace-supers@7.22.20(@babel/core@7.23.6): + resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 dependencies: - '@babel/types': 7.22.4 + '@babel/core': 7.23.6 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + dev: true - /@babel/helper-skip-transparent-expression-wrappers@7.18.9: - resolution: {integrity: sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==} + /@babel/helper-simple-access@7.19.4: + resolution: {integrity: sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.5 dev: true - /@babel/helper-skip-transparent-expression-wrappers@7.20.0: - resolution: {integrity: sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==} + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.5 + + /@babel/helper-skip-transparent-expression-wrappers@7.22.5: + resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 dev: true /@babel/helper-split-export-declaration@7.18.6: resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.5 + dev: true + + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 /@babel/helper-string-parser@7.19.4: resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-string-parser@7.21.5: - resolution: {integrity: sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==} + /@babel/helper-string-parser@7.23.4: + resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} engines: {node: '>=6.9.0'} /@babel/helper-validator-identifier@7.19.1: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} /@babel/helper-validator-option@7.18.6: resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} @@ -1698,16 +1811,18 @@ packages: resolution: {integrity: sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==} engines: {node: '>=6.9.0'} - /@babel/helper-wrap-function@7.19.0: - resolution: {integrity: sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==} + /@babel/helper-validator-option@7.23.5: + resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-wrap-function@7.22.20: + resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-function-name': 7.21.0 - '@babel/template': 7.21.9 - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 - transitivePeerDependencies: - - supports-color + '@babel/helper-function-name': 7.23.0 + '@babel/template': 7.22.15 + '@babel/types': 7.23.5 dev: true /@babel/helpers@7.19.4: @@ -1725,30 +1840,49 @@ packages: resolution: {integrity: sha512-BSY+JSlHxOmGsPTydUkPf1MdMQ3M81x5xGCOVgWM3G8XH77sJ292Y2oqcp0CbbgxhqBuI46iUz1tT7hqP7EfgA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.21.9 - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.5 + '@babel/types': 7.23.5 transitivePeerDependencies: - supports-color - /@babel/helpers@7.22.3: - resolution: {integrity: sha512-jBJ7jWblbgr7r6wYZHMdIqKc73ycaTcCaWRq4/2LpuPHcx7xMlZvpGQkOYc9HeSjn6rcx15CPlgVcBtZ4WZJ2w==} + /@babel/helpers@7.23.5: + resolution: {integrity: sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.21.9 - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.5 + '@babel/types': 7.23.5 transitivePeerDependencies: - supports-color dev: true - /@babel/highlight@7.18.6: - resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} + /@babel/helpers@7.23.6: + resolution: {integrity: sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-validator-identifier': 7.19.1 - chalk: 2.4.2 - js-tokens: 4.0.0 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.6 + '@babel/types': 7.23.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/highlight@7.18.6: + resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + + /@babel/highlight@7.23.4: + resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 /@babel/parser@7.19.6: resolution: {integrity: sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==} @@ -1761,22 +1895,21 @@ packages: resolution: {integrity: sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==} engines: {node: '>=6.0.0'} dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.23.5 - /@babel/parser@7.22.4: - resolution: {integrity: sha512-VLLsx06XkEYqBtE5YGPwfSGwfrjnyPP5oiGty3S8pQLFDFLaS8VwWSIxkTXpcvr5zeYLE6+MBNl2npl/YnfofA==} + /@babel/parser@7.23.5: + resolution: {integrity: sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==} engines: {node: '>=6.0.0'} + hasBin: true dependencies: - '@babel/types': 7.22.4 + '@babel/types': 7.23.5 - /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + /@babel/parser@7.23.6: + resolution: {integrity: sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==} + engines: {node: '>=6.0.0'} + hasBin: true dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/types': 7.23.6 dev: true /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.22.1): @@ -1786,19 +1919,27 @@ packages: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.18.9(@babel/core@7.18.9): - resolution: {integrity: sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==} + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.13.0 + '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.18.9 - '@babel/plugin-proposal-optional-chaining': 7.18.9(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.18.9(@babel/core@7.22.1): @@ -1808,91 +1949,79 @@ packages: '@babel/core': ^7.13.0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-proposal-optional-chaining': 7.18.9(@babel/core@7.22.1) dev: true - /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-6r4yRwEnorYByILoDRnEqxtojYKuiIv9FojW2E8GUKo9eWBwbKcd9IiZOZpdyXc64RmyGGyPu3/uAcrz/dq2kQ==} + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/plugin-transform-optional-chaining': 7.22.3(@babel/core@7.22.1) + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.18.9) dev: true - /@babel/plugin-proposal-async-generator-functions@7.19.1(@babel/core@7.18.9): - resolution: {integrity: sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==} + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.13.0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.18.9) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.18.9) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.5) dev: true - /@babel/plugin-proposal-async-generator-functions@7.19.1(@babel/core@7.22.1): - resolution: {integrity: sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==} + /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.22.1) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.1) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.18.9 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} + /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.18.9) - '@babel/helper-plugin-utils': 7.21.5 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.22.1): - resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} + /@babel/plugin-proposal-async-generator-functions@7.19.1(@babel/core@7.22.1): + resolution: {integrity: sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 - transitivePeerDependencies: - - supports-color + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.22.1) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.1) dev: true - /@babel/plugin-proposal-class-static-block@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==} + /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.12.0 + '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.18.9) - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.18.9) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.22.1 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-proposal-class-static-block@7.18.6(@babel/core@7.22.1): @@ -1902,11 +2031,9 @@ packages: '@babel/core': ^7.12.0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.1) - transitivePeerDependencies: - - supports-color dev: true /@babel/plugin-proposal-decorators@7.19.6(@babel/core@7.22.1): @@ -1916,24 +2043,11 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-replace-supers': 7.19.1 - '@babel/helper-split-export-declaration': 7.18.6 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.22.1) + '@babel/helper-split-export-declaration': 7.22.6 '@babel/plugin-syntax-decorators': 7.19.0(@babel/core@7.22.1) - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.18.9) dev: true /@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.22.1): @@ -1943,7 +2057,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.1) dev: true @@ -1954,7 +2068,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.18.9) dev: true @@ -1965,21 +2079,10 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.1) dev: true - /@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.18.9) - dev: true - /@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.22.1): resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==} engines: {node: '>=6.9.0'} @@ -1987,21 +2090,10 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.1) dev: true - /@babel/plugin-proposal-logical-assignment-operators@7.18.9(@babel/core@7.18.9): - resolution: {integrity: sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.18.9) - dev: true - /@babel/plugin-proposal-logical-assignment-operators@7.18.9(@babel/core@7.22.1): resolution: {integrity: sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==} engines: {node: '>=6.9.0'} @@ -2009,21 +2101,10 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.1) dev: true - /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.18.9) - dev: true - /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.22.1): resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} engines: {node: '>=6.9.0'} @@ -2031,21 +2112,10 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.1) dev: true - /@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.18.9) - dev: true - /@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.22.1): resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} engines: {node: '>=6.9.0'} @@ -2053,47 +2123,22 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.1) dev: true - /@babel/plugin-proposal-object-rest-spread@7.19.4(@babel/core@7.18.9): - resolution: {integrity: sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/compat-data': 7.19.4 - '@babel/core': 7.18.9 - '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.18.9) - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.18.9) - '@babel/plugin-transform-parameters': 7.18.8(@babel/core@7.18.9) - dev: true - /@babel/plugin-proposal-object-rest-spread@7.19.4(@babel/core@7.22.1): resolution: {integrity: sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.19.4 + '@babel/compat-data': 7.23.5 '@babel/core': 7.22.1 - '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-transform-parameters': 7.18.8(@babel/core@7.22.1) - dev: true - - /@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.18.9) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.22.1) dev: true /@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.22.1): @@ -2103,22 +2148,10 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.1) dev: true - /@babel/plugin-proposal-optional-chaining@7.18.9(@babel/core@7.18.9): - resolution: {integrity: sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.18.9 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.18.9) - dev: true - /@babel/plugin-proposal-optional-chaining@7.18.9(@babel/core@7.22.1): resolution: {integrity: sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==} engines: {node: '>=6.9.0'} @@ -2126,24 +2159,11 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.1) dev: true - /@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.18.9 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.18.9) - '@babel/helper-plugin-utils': 7.21.5 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.22.1): resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} engines: {node: '>=6.9.0'} @@ -2151,25 +2171,8 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/plugin-proposal-private-property-in-object@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.18.9 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.18.9) - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.18.9) - transitivePeerDependencies: - - supports-color + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-proposal-private-property-in-object@7.18.6(@babel/core@7.22.1): @@ -2179,38 +2182,28 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.1) - transitivePeerDependencies: - - supports-color dev: true - /@babel/plugin-proposal-private-property-in-object@7.21.0(@babel/core@7.22.1): - resolution: {integrity: sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==} + /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.18.9): + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-create-class-features-plugin': 7.22.1(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.1) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.18.9 dev: true - /@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==} - engines: {node: '>=4'} + /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.5): + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-create-regexp-features-plugin': 7.19.0(@babel/core@7.18.9) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 dev: true /@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.22.1): @@ -2220,8 +2213,8 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-create-regexp-features-plugin': 7.19.0(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.18.9): @@ -2230,7 +2223,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.22.1): @@ -2239,7 +2232,16 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.5): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.18.9): @@ -2248,7 +2250,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.22.1): @@ -2257,7 +2259,16 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.5): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.18.9): @@ -2267,7 +2278,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.22.1): @@ -2277,7 +2288,17 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.23.5): + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-decorators@7.19.0(@babel/core@7.18.9): @@ -2306,7 +2327,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.22.1): @@ -2315,16 +2336,25 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.18.9): + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.23.5): + resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.18.9): resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.22.1): @@ -2333,17 +2363,16 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-import-assertions@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==} - engines: {node: '>=6.9.0'} + /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.23.5): + resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-import-assertions@7.18.6(@babel/core@7.22.1): @@ -2353,36 +2382,65 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-import-assertions@7.20.0(@babel/core@7.22.1): - resolution: {integrity: sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==} + /@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-import-attributes@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-i35jZJv6aO7hxEbIWQ41adVfOzjm9dcYDNeWlBMd8p0ZQRtNUCBrmGwZt+H5lb+oOC9a3svp956KP0oWGA1YsA==} + /@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.22.1): + /@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.18.9): resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.5): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.18.9): @@ -2391,7 +2449,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.22.1): @@ -2400,7 +2458,16 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.5): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-jsx@7.21.4(@babel/core@7.18.9): @@ -2423,13 +2490,23 @@ packages: '@babel/helper-plugin-utils': 7.21.5 dev: true + /@babel/plugin-syntax-jsx@7.21.4(@babel/core@7.23.6): + resolution: {integrity: sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.6 + '@babel/helper-plugin-utils': 7.21.5 + dev: true + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.18.9): resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.22.1): @@ -2438,7 +2515,16 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.5): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.18.9): @@ -2447,7 +2533,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.22.1): @@ -2456,7 +2542,16 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.5): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.18.9): @@ -2465,7 +2560,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.22.1): @@ -2474,7 +2569,16 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.5): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.18.9): @@ -2483,7 +2587,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.22.1): @@ -2492,7 +2596,16 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.5): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.18.9): @@ -2501,7 +2614,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.22.1): @@ -2510,7 +2623,16 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.5): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.18.9): @@ -2519,996 +2641,1299 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.22.1): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.5): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.18.9): + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.22.1): + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.23.5): + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.18.9): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.22.1): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.5): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-typescript@7.20.0(@babel/core@7.22.1): + resolution: {integrity: sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-typescript@7.20.0(@babel/core@7.23.6): + resolution: {integrity: sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.6 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-typescript@7.21.4(@babel/core@7.18.9): + resolution: {integrity: sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.18.9): + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.18.9 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.23.5): + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5) + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-arrow-functions@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-async-generator-functions@7.23.4(@babel/core@7.18.9): + resolution: {integrity: sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.18.9 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.18.9) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.18.9) + dev: true + + /@babel/plugin-transform-async-generator-functions@7.23.4(@babel/core@7.23.5): + resolution: {integrity: sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.5) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.5) + dev: true + + /@babel/plugin-transform-async-to-generator@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.22.1) + dev: true + + /@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.18.9 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.18.9) + dev: true + + /@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.5) + dev: true + + /@babel/plugin-transform-block-scoped-functions@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-block-scoping@7.19.4(@babel/core@7.22.1): + resolution: {integrity: sha512-934S2VLLlt2hRJwPf4MczaOr4hYF0z+VKPwqTNxyKX7NthTiPfhuKFWQZHXRM0vh/wo/VyXB3s4bZUNA08l+tQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.18.9): + resolution: {integrity: sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.23.5): + resolution: {integrity: sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.18.9 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5) + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.18.9): + resolution: {integrity: sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + dependencies: + '@babel/core': 7.18.9 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.18.9) + dev: true + + /@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.23.5): + resolution: {integrity: sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.5) + dev: true + + /@babel/plugin-transform-classes@7.19.0(@babel/core@7.22.1): + resolution: {integrity: sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.22.1) + '@babel/helper-split-export-declaration': 7.22.6 + globals: 11.12.0 dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.22.1): - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + /@babel/plugin-transform-classes@7.23.5(@babel/core@7.18.9): + resolution: {integrity: sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.18.9 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.18.9) + '@babel/helper-split-export-declaration': 7.22.6 + globals: 11.12.0 dev: true - /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.18.9): - resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + /@babel/plugin-transform-classes@7.23.5(@babel/core@7.23.5): + resolution: {integrity: sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.5) + '@babel/helper-split-export-declaration': 7.22.6 + globals: 11.12.0 dev: true - /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.22.1): - resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + /@babel/plugin-transform-computed-properties@7.18.9(@babel/core@7.22.1): + resolution: {integrity: sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.18.9): - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + /@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/template': 7.22.15 dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.22.1): - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + /@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/template': 7.22.15 dev: true - /@babel/plugin-syntax-typescript@7.20.0(@babel/core@7.18.9): - resolution: {integrity: sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==} + /@babel/plugin-transform-destructuring@7.19.4(@babel/core@7.22.1): + resolution: {integrity: sha512-t0j0Hgidqf0aM86dF8U+vXYReUgJnlv4bZLsyoPnwZNrGY+7/38o8YjaELrvHeVfTZao15kjR0PVv0nju2iduA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-typescript@7.20.0(@babel/core@7.22.1): - resolution: {integrity: sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==} + /@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-typescript@7.21.4(@babel/core@7.18.9): - resolution: {integrity: sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==} + /@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.22.1): - resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + /@babel/plugin-transform-dotall-regex@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-create-regexp-features-plugin': 7.22.1(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-arrow-functions@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==} + /@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-arrow-functions@7.18.6(@babel/core@7.22.1): - resolution: {integrity: sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==} + /@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.22.1): + resolution: {integrity: sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-arrow-functions@7.21.5(@babel/core@7.22.1): - resolution: {integrity: sha512-wb1mhwGOCaXHDTcsRYMKF9e5bbMgqwxtqa2Y1ifH96dXJPwbuLX9qHy3clhrxVqgMz7nyNXs8VkxdH8UBcjKqA==} + /@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-async-generator-functions@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-36A4Aq48t66btydbZd5Fk0/xJqbpg/v4QWI4AH4cYHBXy9Mu42UOupZpebKFiCFNT9S9rJFcsld0gsv0ayLjtA==} + /@babel/plugin-transform-duplicate-keys@7.18.9(@babel/core@7.22.1): + resolution: {integrity: sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.22.1) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.1) - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-async-to-generator@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==} + /@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-module-imports': 7.21.4 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.18.9) - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-async-to-generator@7.18.6(@babel/core@7.22.1): - resolution: {integrity: sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==} + /@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-module-imports': 7.21.4 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.22.1) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-async-to-generator@7.20.7(@babel/core@7.22.1): - resolution: {integrity: sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==} + /@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.18.9): + resolution: {integrity: sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-module-imports': 7.21.4 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.22.1) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.18.9) dev: true - /@babel/plugin-transform-block-scoped-functions@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==} + /@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.23.5): + resolution: {integrity: sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.5) dev: true - /@babel/plugin-transform-block-scoped-functions@7.18.6(@babel/core@7.22.1): - resolution: {integrity: sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==} + /@babel/plugin-transform-exponentiation-operator@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-block-scoping@7.19.4(@babel/core@7.18.9): - resolution: {integrity: sha512-934S2VLLlt2hRJwPf4MczaOr4hYF0z+VKPwqTNxyKX7NthTiPfhuKFWQZHXRM0vh/wo/VyXB3s4bZUNA08l+tQ==} + /@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-block-scoping@7.19.4(@babel/core@7.22.1): - resolution: {integrity: sha512-934S2VLLlt2hRJwPf4MczaOr4hYF0z+VKPwqTNxyKX7NthTiPfhuKFWQZHXRM0vh/wo/VyXB3s4bZUNA08l+tQ==} + /@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-block-scoping@7.21.0(@babel/core@7.22.1): - resolution: {integrity: sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==} + /@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.18.9): + resolution: {integrity: sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.18.9) dev: true - /@babel/plugin-transform-class-properties@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-mASLsd6rhOrLZ5F3WbCxkzl67mmOnqik0zrg5W6D/X0QMW7HtvnoL1dRARLKIbMP3vXwkwziuLesPqWVGIl6Bw==} + /@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.23.5): + resolution: {integrity: sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-create-class-features-plugin': 7.22.1(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.5) dev: true - /@babel/plugin-transform-class-static-block@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-5BirgNWNOx7cwbTJCOmKFJ1pZjwk5MUfMIwiBBvsirCJMZeQgs5pk6i1OlkVg+1Vef5LfBahFOrdCnAWvkVKMw==} + /@babel/plugin-transform-for-of@7.18.8(@babel/core@7.22.1): + resolution: {integrity: sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.12.0 + '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-create-class-features-plugin': 7.22.1(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.1) - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-classes@7.19.0(@babel/core@7.18.9): - resolution: {integrity: sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==} + /@babel/plugin-transform-for-of@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-compilation-targets': 7.21.5(@babel/core@7.18.9) - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.19.0 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-replace-supers': 7.19.1 - '@babel/helper-split-export-declaration': 7.18.6 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-classes@7.19.0(@babel/core@7.22.1): - resolution: {integrity: sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==} + /@babel/plugin-transform-for-of@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-compilation-targets': 7.21.5(@babel/core@7.22.1) - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.19.0 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-replace-supers': 7.19.1 - '@babel/helper-split-export-declaration': 7.18.6 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-classes@7.21.0(@babel/core@7.22.1): - resolution: {integrity: sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==} + /@babel/plugin-transform-function-name@7.18.9(@babel/core@7.22.1): + resolution: {integrity: sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1) - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-function-name': 7.21.0 - '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-replace-supers': 7.22.1 - '@babel/helper-split-export-declaration': 7.18.6 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color + '@babel/helper-compilation-targets': 7.18.9(@babel/core@7.22.1) + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-computed-properties@7.18.9(@babel/core@7.18.9): - resolution: {integrity: sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==} + /@babel/plugin-transform-function-name@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - dev: true - - /@babel/plugin-transform-computed-properties@7.18.9(@babel/core@7.22.1): - resolution: {integrity: sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-computed-properties@7.21.5(@babel/core@7.22.1): - resolution: {integrity: sha512-TR653Ki3pAwxBxUe8srfF3e4Pe3FTA46uaNHYyQwIoM4oWKSoOZiDNyHJ0oIoDIUPSRQbQG7jzgVBX3FPVne1Q==} + /@babel/plugin-transform-function-name@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/template': 7.21.9 + '@babel/core': 7.23.5 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-destructuring@7.19.4(@babel/core@7.18.9): - resolution: {integrity: sha512-t0j0Hgidqf0aM86dF8U+vXYReUgJnlv4bZLsyoPnwZNrGY+7/38o8YjaELrvHeVfTZao15kjR0PVv0nju2iduA==} + /@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.18.9): + resolution: {integrity: sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.18.9) dev: true - /@babel/plugin-transform-destructuring@7.19.4(@babel/core@7.22.1): - resolution: {integrity: sha512-t0j0Hgidqf0aM86dF8U+vXYReUgJnlv4bZLsyoPnwZNrGY+7/38o8YjaELrvHeVfTZao15kjR0PVv0nju2iduA==} + /@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.23.5): + resolution: {integrity: sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.5) dev: true - /@babel/plugin-transform-destructuring@7.21.3(@babel/core@7.22.1): - resolution: {integrity: sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA==} + /@babel/plugin-transform-literals@7.18.9(@babel/core@7.22.1): + resolution: {integrity: sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-dotall-regex@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==} + /@babel/plugin-transform-literals@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-create-regexp-features-plugin': 7.19.0(@babel/core@7.18.9) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-dotall-regex@7.18.6(@babel/core@7.22.1): - resolution: {integrity: sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==} + /@babel/plugin-transform-literals@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-create-regexp-features-plugin': 7.19.0(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-duplicate-keys@7.18.9(@babel/core@7.18.9): - resolution: {integrity: sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==} + /@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.18.9): + resolution: {integrity: sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.18.9) dev: true - /@babel/plugin-transform-duplicate-keys@7.18.9(@babel/core@7.22.1): - resolution: {integrity: sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==} + /@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.23.5): + resolution: {integrity: sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.5) dev: true - /@babel/plugin-transform-dynamic-import@7.22.1(@babel/core@7.22.1): - resolution: {integrity: sha512-rlhWtONnVBPdmt+jeewS0qSnMz/3yLFrqAP8hHC6EDcrYRSyuz9f9yQhHvVn2Ad6+yO9fHXac5piudeYrInxwQ==} + /@babel/plugin-transform-member-expression-literals@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-exponentiation-operator@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==} + /@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-exponentiation-operator@7.18.6(@babel/core@7.22.1): - resolution: {integrity: sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==} + /@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-export-namespace-from@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-5Ti1cHLTDnt3vX61P9KZ5IG09bFXp4cDVFJIAeCZuxu9OXXJJZp5iP0n/rzM2+iAutJY+KWEyyHcRaHlpQ/P5g==} + /@babel/plugin-transform-modules-amd@7.19.6(@babel/core@7.22.1): + resolution: {integrity: sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.1) + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-for-of@7.18.8(@babel/core@7.18.9): - resolution: {integrity: sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==} + /@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-for-of@7.18.8(@babel/core@7.22.1): - resolution: {integrity: sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==} + /@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-for-of@7.21.5(@babel/core@7.22.1): - resolution: {integrity: sha512-nYWpjKW/7j/I/mZkGVgHJXh4bA1sfdFnJoOXwJuj4m3Q2EraO/8ZyrkCau9P5tbHQk01RMSt6KYLCsW7730SXQ==} + /@babel/plugin-transform-modules-commonjs@7.19.6(@babel/core@7.18.9): + resolution: {integrity: sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.18.9 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-simple-access': 7.22.5 dev: true - /@babel/plugin-transform-function-name@7.18.9(@babel/core@7.18.9): - resolution: {integrity: sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==} + /@babel/plugin-transform-modules-commonjs@7.19.6(@babel/core@7.22.1): + resolution: {integrity: sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-compilation-targets': 7.18.9(@babel/core@7.18.9) - '@babel/helper-function-name': 7.19.0 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.22.1 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-simple-access': 7.22.5 dev: true - /@babel/plugin-transform-function-name@7.18.9(@babel/core@7.22.1): - resolution: {integrity: sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==} + /@babel/plugin-transform-modules-commonjs@7.21.5(@babel/core@7.18.9): + resolution: {integrity: sha512-OVryBEgKUbtqMoB7eG2rs6UFexJi6Zj6FDXx+esBLPTCxCNxAY9o+8Di7IsUGJ+AVhp5ncK0fxWUBd0/1gPhrQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-compilation-targets': 7.18.9(@babel/core@7.22.1) - '@babel/helper-function-name': 7.19.0 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.18.9 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-simple-access': 7.22.5 dev: true - /@babel/plugin-transform-json-strings@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-IuvOMdeOOY2X4hRNAT6kwbePtK21BUyrAEgLKviL8pL6AEEVUVcqtRdN/HJXBLGIbt9T3ETmXRnFedRRmQNTYw==} + /@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.1) + '@babel/core': 7.18.9 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-simple-access': 7.22.5 dev: true - /@babel/plugin-transform-literals@7.18.9(@babel/core@7.18.9): - resolution: {integrity: sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==} + /@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-simple-access': 7.22.5 dev: true - /@babel/plugin-transform-literals@7.18.9(@babel/core@7.22.1): - resolution: {integrity: sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==} + /@babel/plugin-transform-modules-systemjs@7.19.6(@babel/core@7.22.1): + resolution: {integrity: sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 dev: true - /@babel/plugin-transform-logical-assignment-operators@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-CbayIfOw4av2v/HYZEsH+Klks3NC2/MFIR3QR8gnpGNNPEaq2fdlVCRYG/paKs7/5hvBLQ+H70pGWOHtlNEWNA==} + /@babel/plugin-transform-modules-systemjs@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.1) + '@babel/core': 7.18.9 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 dev: true - /@babel/plugin-transform-member-expression-literals@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==} + /@babel/plugin-transform-modules-systemjs@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 dev: true - /@babel/plugin-transform-member-expression-literals@7.18.6(@babel/core@7.22.1): - resolution: {integrity: sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==} + /@babel/plugin-transform-modules-umd@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-modules-amd@7.19.6(@babel/core@7.18.9): - resolution: {integrity: sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==} + /@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-module-transforms': 7.21.5 - '@babel/helper-plugin-utils': 7.21.5 - transitivePeerDependencies: - - supports-color + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-modules-amd@7.19.6(@babel/core@7.22.1): - resolution: {integrity: sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==} + /@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-module-transforms': 7.21.5 - '@babel/helper-plugin-utils': 7.21.5 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.5 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5) + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-named-capturing-groups-regex@7.19.1(@babel/core@7.22.1): + resolution: {integrity: sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-modules-amd@7.20.11(@babel/core@7.22.1): - resolution: {integrity: sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==} + /@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.18.9): + resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-module-transforms': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.18.9 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-modules-commonjs@7.19.6(@babel/core@7.18.9): - resolution: {integrity: sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==} + /@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.23.5): + resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-module-transforms': 7.21.5 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-simple-access': 7.21.5 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-modules-commonjs@7.19.6(@babel/core@7.22.1): - resolution: {integrity: sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==} + /@babel/plugin-transform-new-target@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-module-transforms': 7.21.5 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-simple-access': 7.21.5 - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-modules-commonjs@7.21.5(@babel/core@7.18.9): - resolution: {integrity: sha512-OVryBEgKUbtqMoB7eG2rs6UFexJi6Zj6FDXx+esBLPTCxCNxAY9o+8Di7IsUGJ+AVhp5ncK0fxWUBd0/1gPhrQ==} + /@babel/plugin-transform-new-target@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-module-transforms': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-simple-access': 7.21.5 - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-modules-commonjs@7.21.5(@babel/core@7.22.1): - resolution: {integrity: sha512-OVryBEgKUbtqMoB7eG2rs6UFexJi6Zj6FDXx+esBLPTCxCNxAY9o+8Di7IsUGJ+AVhp5ncK0fxWUBd0/1gPhrQ==} + /@babel/plugin-transform-new-target@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-module-transforms': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-simple-access': 7.21.5 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-modules-systemjs@7.19.6(@babel/core@7.18.9): - resolution: {integrity: sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==} + /@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.18.9): + resolution: {integrity: sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-module-transforms': 7.21.5 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-validator-identifier': 7.19.1 - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.18.9) dev: true - /@babel/plugin-transform-modules-systemjs@7.19.6(@babel/core@7.22.1): - resolution: {integrity: sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==} + /@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.23.5): + resolution: {integrity: sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-module-transforms': 7.21.5 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-validator-identifier': 7.19.1 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.5) dev: true - /@babel/plugin-transform-modules-systemjs@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-V21W3bKLxO3ZjcBJZ8biSvo5gQ85uIXW2vJfh7JSWf/4SLUSr1tOoHX3ruN4+Oqa2m+BKfsxTR1I+PsvkIWvNw==} + /@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.18.9): + resolution: {integrity: sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-module-transforms': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-validator-identifier': 7.19.1 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.18.9) dev: true - /@babel/plugin-transform-modules-umd@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==} + /@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.23.5): + resolution: {integrity: sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-module-transforms': 7.21.5 - '@babel/helper-plugin-utils': 7.21.5 - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.5) dev: true - /@babel/plugin-transform-modules-umd@7.18.6(@babel/core@7.22.1): - resolution: {integrity: sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==} + /@babel/plugin-transform-object-assign@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-mQisZ3JfqWh2gVXvfqYCAAyRs6+7oev+myBsTwW5RnPhYXOTuCEw2oe3YgxlXMViXUS53lG8koulI7mJ+8JE+A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-module-transforms': 7.21.5 - '@babel/helper-plugin-utils': 7.21.5 - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-named-capturing-groups-regex@7.19.1(@babel/core@7.18.9): - resolution: {integrity: sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==} + /@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.18.9): + resolution: {integrity: sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.0.0-0 dependencies: + '@babel/compat-data': 7.23.5 '@babel/core': 7.18.9 - '@babel/helper-create-regexp-features-plugin': 7.19.0(@babel/core@7.18.9) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.18.9) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.18.9) dev: true - /@babel/plugin-transform-named-capturing-groups-regex@7.19.1(@babel/core@7.22.1): - resolution: {integrity: sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==} + /@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.23.5): + resolution: {integrity: sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-create-regexp-features-plugin': 7.19.0(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/compat-data': 7.23.5 + '@babel/core': 7.23.5 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.5) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.5) dev: true - /@babel/plugin-transform-named-capturing-groups-regex@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-c6HrD/LpUdNNJsISQZpds3TXvfYIAbo+efE9aWmY/PmSRD0agrJ9cPMt4BmArwUQ7ZymEWTFjTyp+yReLJZh0Q==} + /@babel/plugin-transform-object-super@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-create-regexp-features-plugin': 7.22.1(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.22.1) dev: true - /@babel/plugin-transform-new-target@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==} + /@babel/plugin-transform-object-super@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.18.9) dev: true - /@babel/plugin-transform-new-target@7.18.6(@babel/core@7.22.1): - resolution: {integrity: sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==} + /@babel/plugin-transform-object-super@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.5) dev: true - /@babel/plugin-transform-new-target@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-5RuJdSo89wKdkRTqtM9RVVJzHum9c2s0te9rB7vZC1zKKxcioWIy+xcu4OoIAjyFZhb/bp5KkunuLin1q7Ct+w==} + /@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.18.9): + resolution: {integrity: sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.18.9) dev: true - /@babel/plugin-transform-nullish-coalescing-operator@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-CpaoNp16nX7ROtLONNuCyenYdY/l7ZsR6aoVa7rW7nMWisoNoQNIH5Iay/4LDyRjKMuElMqXiBoOQCDLTMGZiw==} + /@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.23.5): + resolution: {integrity: sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.1) + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.5) dev: true - /@babel/plugin-transform-numeric-separator@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-+AF88fPDJrnseMh5vD9+SH6wq4ZMvpiTMHh58uLs+giMEyASFVhcT3NkoyO+NebFCNnpHJEq5AXO2txV4AGPDQ==} + /@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.18.9): + resolution: {integrity: sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.1) + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.18.9) dev: true - /@babel/plugin-transform-object-assign@7.18.6(@babel/core@7.22.1): - resolution: {integrity: sha512-mQisZ3JfqWh2gVXvfqYCAAyRs6+7oev+myBsTwW5RnPhYXOTuCEw2oe3YgxlXMViXUS53lG8koulI7mJ+8JE+A==} + /@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.23.5): + resolution: {integrity: sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.5) dev: true - /@babel/plugin-transform-object-rest-spread@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-38bzTsqMMCI46/TQnJwPPpy33EjLCc1Gsm2hRTF6zTMWnKsN61vdrpuzIEGQyKEhDSYDKyZHrrd5FMj4gcUHhw==} + /@babel/plugin-transform-parameters@7.18.8(@babel/core@7.22.1): + resolution: {integrity: sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.22.3 '@babel/core': 7.22.1 - '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-transform-parameters': 7.22.3(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-object-super@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==} + /@babel/plugin-transform-parameters@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-replace-supers': 7.19.1 - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-object-super@7.18.6(@babel/core@7.22.1): - resolution: {integrity: sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==} + /@babel/plugin-transform-parameters@7.23.3(@babel/core@7.22.1): + resolution: {integrity: sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-replace-supers': 7.19.1 - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-optional-catch-binding@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-bnDFWXFzWY0BsOyqaoSXvMQ2F35zutQipugog/rqotL2S4ciFOKlRYUu9djt4iq09oh2/34hqfRR2k1dIvuu4g==} + /@babel/plugin-transform-parameters@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.1) + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-optional-chaining@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-63v3/UFFxhPKT8j8u1jTTGVyITxl7/7AfOqK8C5gz1rHURPUGe3y5mvIf68eYKGoBNahtJnTxBKug4BQOnzeJg==} + /@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.1) + '@babel/core': 7.18.9 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-parameters@7.18.8(@babel/core@7.18.9): - resolution: {integrity: sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==} + /@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-parameters@7.18.8(@babel/core@7.22.1): - resolution: {integrity: sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==} + /@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.18.9): + resolution: {integrity: sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.18.9 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.18.9) dev: true - /@babel/plugin-transform-parameters@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-x7QHQJHPuD9VmfpzboyGJ5aHEr9r7DsAsdxdhJiTB3J3j8dyl+NFZ+rX5Q2RWFDCs61c06qBfS4ys2QYn8UkMw==} + /@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.23.5): + resolution: {integrity: sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.5) dev: true - /@babel/plugin-transform-private-methods@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-fC7jtjBPFqhqpPAE+O4LKwnLq7gGkD3ZmC2E3i4qWH34mH3gOg2Xrq5YMHUq6DM30xhqM1DNftiRaSqVjEG+ug==} + /@babel/plugin-transform-property-literals@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-create-class-features-plugin': 7.22.1(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-private-property-in-object@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-C7MMl4qWLpgVCbXfj3UW8rR1xeCnisQ0cU7YJHV//8oNBS0aCIVg1vFnZXxOckHhEpQyqNNkWmvSEWnMLlc+Vw==} + /@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-create-class-features-plugin': 7.22.1(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.1) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-property-literals@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==} + /@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-property-literals@7.18.6(@babel/core@7.22.1): - resolution: {integrity: sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==} + /@babel/plugin-transform-react-display-name@7.18.6(@babel/core@7.18.9): + resolution: {integrity: sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-react-display-name@7.18.6(@babel/core@7.18.9): + /@babel/plugin-transform-react-display-name@7.18.6(@babel/core@7.23.6): resolution: {integrity: sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.6 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-transform-react-jsx-development@7.18.6(@babel/core@7.18.9): @@ -3521,6 +3946,16 @@ packages: '@babel/plugin-transform-react-jsx': 7.22.3(@babel/core@7.18.9) dev: true + /@babel/plugin-transform-react-jsx-development@7.18.6(@babel/core@7.23.6): + resolution: {integrity: sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.6 + '@babel/plugin-transform-react-jsx': 7.22.3(@babel/core@7.23.6) + dev: true + /@babel/plugin-transform-react-jsx@7.19.0(@babel/core@7.22.1): resolution: {integrity: sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==} engines: {node: '>=6.9.0'} @@ -3528,11 +3963,11 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-module-imports': 7.21.4 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-jsx': 7.21.4(@babel/core@7.22.1) - '@babel/types': 7.22.4 + '@babel/types': 7.23.5 dev: true /@babel/plugin-transform-react-jsx@7.22.3(@babel/core@7.18.9): @@ -3542,11 +3977,25 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-module-imports': 7.21.4 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-jsx': 7.21.4(@babel/core@7.18.9) - '@babel/types': 7.22.4 + '@babel/types': 7.23.5 + dev: true + + /@babel/plugin-transform-react-jsx@7.22.3(@babel/core@7.23.6): + resolution: {integrity: sha512-JEulRWG2f04a7L8VWaOngWiK6p+JOSpB+DAtwfJgOaej1qdbNxqtK7MwTBHjUA10NeFcszlFNqCdbRcirzh2uQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.6 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-jsx': 7.21.4(@babel/core@7.23.6) + '@babel/types': 7.23.5 dev: true /@babel/plugin-transform-react-pure-annotations@7.18.6(@babel/core@7.18.9): @@ -3556,19 +4005,19 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-regenerator@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==} + /@babel/plugin-transform-react-pure-annotations@7.18.6(@babel/core@7.23.6): + resolution: {integrity: sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - regenerator-transform: 0.15.0 + '@babel/core': 7.23.6 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-transform-regenerator@7.18.6(@babel/core@7.22.1): @@ -3578,29 +4027,30 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - regenerator-transform: 0.15.0 + '@babel/helper-plugin-utils': 7.22.5 + regenerator-transform: 0.15.2 dev: true - /@babel/plugin-transform-regenerator@7.21.5(@babel/core@7.22.1): - resolution: {integrity: sha512-ZoYBKDb6LyMi5yCsByQ5jmXsHAQDDYeexT1Szvlmui+lADvfSecr5Dxd/PkrTC3pAD182Fcju1VQkB4oCp9M+w==} + /@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - regenerator-transform: 0.15.1 + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + regenerator-transform: 0.15.2 dev: true - /@babel/plugin-transform-reserved-words@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==} + /@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + regenerator-transform: 0.15.2 dev: true /@babel/plugin-transform-reserved-words@7.18.6(@babel/core@7.22.1): @@ -3610,24 +4060,27 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-runtime@7.19.6(@babel/core@7.18.9): - resolution: {integrity: sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==} + /@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-module-imports': 7.21.4 - '@babel/helper-plugin-utils': 7.21.5 - babel-plugin-polyfill-corejs2: 0.3.3(@babel/core@7.18.9) - babel-plugin-polyfill-corejs3: 0.6.0(@babel/core@7.18.9) - babel-plugin-polyfill-regenerator: 0.4.1(@babel/core@7.18.9) - semver: 6.3.0 - transitivePeerDependencies: - - supports-color + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-transform-runtime@7.19.6(@babel/core@7.22.1): @@ -3647,14 +4100,38 @@ packages: - supports-color dev: true - /@babel/plugin-transform-shorthand-properties@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==} + /@babel/plugin-transform-runtime@7.23.4(@babel/core@7.18.9): + resolution: {integrity: sha512-ITwqpb6V4btwUG0YJR82o2QvmWrLgDnx/p2A3CTPYGaRgULkDiC0DRA2C4jlRB9uXGUEfaSS/IGHfVW+ohzYDw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + babel-plugin-polyfill-corejs2: 0.4.6(@babel/core@7.18.9) + babel-plugin-polyfill-corejs3: 0.8.6(@babel/core@7.18.9) + babel-plugin-polyfill-regenerator: 0.5.3(@babel/core@7.18.9) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-runtime@7.23.4(@babel/core@7.23.5): + resolution: {integrity: sha512-ITwqpb6V4btwUG0YJR82o2QvmWrLgDnx/p2A3CTPYGaRgULkDiC0DRA2C4jlRB9uXGUEfaSS/IGHfVW+ohzYDw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + babel-plugin-polyfill-corejs2: 0.4.6(@babel/core@7.23.5) + babel-plugin-polyfill-corejs3: 0.8.6(@babel/core@7.23.5) + babel-plugin-polyfill-regenerator: 0.5.3(@babel/core@7.23.5) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color dev: true /@babel/plugin-transform-shorthand-properties@7.18.6(@babel/core@7.22.1): @@ -3664,18 +4141,27 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-spread@7.19.0(@babel/core@7.18.9): - resolution: {integrity: sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==} + /@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-transform-spread@7.19.0(@babel/core@7.22.1): @@ -3685,33 +4171,64 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + dev: true + + /@babel/plugin-transform-spread@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + dev: true + + /@babel/plugin-transform-spread@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + dev: true + + /@babel/plugin-transform-sticky-regex@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-spread@7.20.7(@babel/core@7.22.1): - resolution: {integrity: sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==} + /@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-sticky-regex@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==} + /@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-sticky-regex@7.18.6(@babel/core@7.22.1): - resolution: {integrity: sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==} + /@babel/plugin-transform-template-literals@7.18.9(@babel/core@7.22.1): + resolution: {integrity: sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -3720,58 +4237,54 @@ packages: '@babel/helper-plugin-utils': 7.21.5 dev: true - /@babel/plugin-transform-template-literals@7.18.9(@babel/core@7.18.9): - resolution: {integrity: sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==} + /@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-template-literals@7.18.9(@babel/core@7.22.1): - resolution: {integrity: sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==} + /@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-typeof-symbol@7.18.9(@babel/core@7.18.9): + /@babel/plugin-transform-typeof-symbol@7.18.9(@babel/core@7.22.1): resolution: {integrity: sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-typeof-symbol@7.18.9(@babel/core@7.22.1): - resolution: {integrity: sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==} + /@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-typescript@7.20.13(@babel/core@7.18.9): - resolution: {integrity: sha512-O7I/THxarGcDZxkgWKMUrk7NK1/WbHAg3Xx86gqS6x9MTrNL6AwIluuZ96ms4xeDe6AVx6rjHbWHP7x26EPQBA==} + /@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.18.9) - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-typescript': 7.20.0(@babel/core@7.18.9) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-transform-typescript@7.20.13(@babel/core@7.22.1): @@ -3781,36 +4294,34 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-create-class-features-plugin': 7.20.12(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-typescript': 7.20.0(@babel/core@7.22.1) - transitivePeerDependencies: - - supports-color dev: true - /@babel/plugin-transform-typescript@7.22.3(@babel/core@7.18.9): - resolution: {integrity: sha512-pyjnCIniO5PNaEuGxT28h0HbMru3qCVrMqVgVOz/krComdIrY9W6FCLBq9NWHY8HDGaUlan+UhmZElDENIfCcw==} + /@babel/plugin-transform-typescript@7.20.13(@babel/core@7.23.6): + resolution: {integrity: sha512-O7I/THxarGcDZxkgWKMUrk7NK1/WbHAg3Xx86gqS6x9MTrNL6AwIluuZ96ms4xeDe6AVx6rjHbWHP7x26EPQBA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-create-class-features-plugin': 7.22.1(@babel/core@7.18.9) - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-syntax-typescript': 7.21.4(@babel/core@7.18.9) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.6 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.6) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-typescript': 7.20.0(@babel/core@7.23.6) dev: true - /@babel/plugin-transform-unicode-escapes@7.18.10(@babel/core@7.18.9): - resolution: {integrity: sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==} + /@babel/plugin-transform-typescript@7.22.3(@babel/core@7.18.9): + resolution: {integrity: sha512-pyjnCIniO5PNaEuGxT28h0HbMru3qCVrMqVgVOz/krComdIrY9W6FCLBq9NWHY8HDGaUlan+UhmZElDENIfCcw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-typescript': 7.21.4(@babel/core@7.18.9) dev: true /@babel/plugin-transform-unicode-escapes@7.18.10(@babel/core@7.22.1): @@ -3820,39 +4331,49 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-unicode-escapes@7.21.5(@babel/core@7.22.1): - resolution: {integrity: sha512-LYm/gTOwZqsYohlvFUe/8Tujz75LqqVC2w+2qPHLR+WyWHGCZPN1KBpJCJn+4Bk4gOkQy/IXKIge6az5MqwlOg==} + /@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-unicode-property-regex@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-5ScJ+OmdX+O6HRuMGW4kv7RL9vIKdtdAj9wuWUKy1wbHY3jaM/UlyIiC1G7J6UJiiyMukjjK0QwL3P0vBd0yYg==} + /@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-create-regexp-features-plugin': 7.22.1(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-unicode-regex@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==} + /@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.9 - '@babel/helper-create-regexp-features-plugin': 7.19.0(@babel/core@7.18.9) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5) + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/plugin-transform-unicode-regex@7.18.6(@babel/core@7.22.1): @@ -3862,105 +4383,52 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-create-regexp-features-plugin': 7.19.0(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/plugin-transform-unicode-sets-regex@7.22.3(@babel/core@7.22.1): - resolution: {integrity: sha512-hNufLdkF8vqywRp+P55j4FHXqAX2LRUccoZHH7AFn1pq5ZOO2ISKW9w13bFZVjBoTqeve2HOgoJCcaziJVhGNw==} + /@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-create-regexp-features-plugin': 7.22.1(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 + '@babel/core': 7.18.9 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 dev: true - /@babel/preset-env@7.19.4(@babel/core@7.18.9): - resolution: {integrity: sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==} + /@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.19.4 + '@babel/core': 7.23.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5) + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.18.9): + resolution: {integrity: sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: '@babel/core': 7.18.9 - '@babel/helper-compilation-targets': 7.21.5(@babel/core@7.18.9) - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-validator-option': 7.21.0 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.18.9(@babel/core@7.18.9) - '@babel/plugin-proposal-async-generator-functions': 7.19.1(@babel/core@7.18.9) - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-proposal-class-static-block': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-proposal-dynamic-import': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-proposal-export-namespace-from': 7.18.9(@babel/core@7.18.9) - '@babel/plugin-proposal-json-strings': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-proposal-logical-assignment-operators': 7.18.9(@babel/core@7.18.9) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-proposal-object-rest-spread': 7.19.4(@babel/core@7.18.9) - '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-proposal-optional-chaining': 7.18.9(@babel/core@7.18.9) - '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-proposal-private-property-in-object': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.18.9) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.18.9) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.18.9) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.18.9) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.18.9) - '@babel/plugin-syntax-import-assertions': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.18.9) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.18.9) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.18.9) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.18.9) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.18.9) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.18.9) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.18.9) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.18.9) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.18.9) - '@babel/plugin-transform-arrow-functions': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-async-to-generator': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-block-scoped-functions': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-block-scoping': 7.19.4(@babel/core@7.18.9) - '@babel/plugin-transform-classes': 7.19.0(@babel/core@7.18.9) - '@babel/plugin-transform-computed-properties': 7.18.9(@babel/core@7.18.9) - '@babel/plugin-transform-destructuring': 7.19.4(@babel/core@7.18.9) - '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-duplicate-keys': 7.18.9(@babel/core@7.18.9) - '@babel/plugin-transform-exponentiation-operator': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-for-of': 7.18.8(@babel/core@7.18.9) - '@babel/plugin-transform-function-name': 7.18.9(@babel/core@7.18.9) - '@babel/plugin-transform-literals': 7.18.9(@babel/core@7.18.9) - '@babel/plugin-transform-member-expression-literals': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-modules-amd': 7.19.6(@babel/core@7.18.9) - '@babel/plugin-transform-modules-commonjs': 7.19.6(@babel/core@7.18.9) - '@babel/plugin-transform-modules-systemjs': 7.19.6(@babel/core@7.18.9) - '@babel/plugin-transform-modules-umd': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-named-capturing-groups-regex': 7.19.1(@babel/core@7.18.9) - '@babel/plugin-transform-new-target': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-object-super': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-parameters': 7.18.8(@babel/core@7.18.9) - '@babel/plugin-transform-property-literals': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-regenerator': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-reserved-words': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-shorthand-properties': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-spread': 7.19.0(@babel/core@7.18.9) - '@babel/plugin-transform-sticky-regex': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-template-literals': 7.18.9(@babel/core@7.18.9) - '@babel/plugin-transform-typeof-symbol': 7.18.9(@babel/core@7.18.9) - '@babel/plugin-transform-unicode-escapes': 7.18.10(@babel/core@7.18.9) - '@babel/plugin-transform-unicode-regex': 7.18.6(@babel/core@7.18.9) - '@babel/preset-modules': 0.1.5(@babel/core@7.18.9) - '@babel/types': 7.22.4 - babel-plugin-polyfill-corejs2: 0.3.3(@babel/core@7.18.9) - babel-plugin-polyfill-corejs3: 0.6.0(@babel/core@7.18.9) - babel-plugin-polyfill-regenerator: 0.4.1(@babel/core@7.18.9) - core-js-compat: 3.26.0 - semver: 6.3.0 - transitivePeerDependencies: - - supports-color + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.18.9) + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.23.5): + resolution: {integrity: sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.5) + '@babel/helper-plugin-utils': 7.22.5 dev: true /@babel/preset-env@7.19.4(@babel/core@7.22.1): @@ -4049,108 +4517,186 @@ packages: - supports-color dev: true - /@babel/preset-env@7.22.4(@babel/core@7.22.1): - resolution: {integrity: sha512-c3lHOjbwBv0TkhYCr+XCR6wKcSZ1QbQTVdSkZUaVpLv8CVWotBMArWUi5UAJrcrQaEnleVkkvaV8F/pmc/STZQ==} + /@babel/preset-env@7.23.5(@babel/core@7.18.9): + resolution: {integrity: sha512-0d/uxVD6tFGWXGDSfyMD1p2otoaKmu6+GD+NfAx0tMaH+dxORnp7T9TaVQ6mKyya7iBtCIVxHjWT7MuzzM9z+A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.22.3 - '@babel/core': 7.22.1 - '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1) - '@babel/helper-plugin-utils': 7.21.5 - '@babel/helper-validator-option': 7.21.0 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.18.6(@babel/core@7.22.1) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-proposal-private-property-in-object': 7.21.0(@babel/core@7.22.1) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.1) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.22.1) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.1) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-syntax-import-assertions': 7.20.0(@babel/core@7.22.1) - '@babel/plugin-syntax-import-attributes': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.22.1) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.1) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.1) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.1) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.1) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.22.1) - '@babel/plugin-transform-arrow-functions': 7.21.5(@babel/core@7.22.1) - '@babel/plugin-transform-async-generator-functions': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-async-to-generator': 7.20.7(@babel/core@7.22.1) - '@babel/plugin-transform-block-scoped-functions': 7.18.6(@babel/core@7.22.1) - '@babel/plugin-transform-block-scoping': 7.21.0(@babel/core@7.22.1) - '@babel/plugin-transform-class-properties': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-class-static-block': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-classes': 7.21.0(@babel/core@7.22.1) - '@babel/plugin-transform-computed-properties': 7.21.5(@babel/core@7.22.1) - '@babel/plugin-transform-destructuring': 7.21.3(@babel/core@7.22.1) - '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.22.1) - '@babel/plugin-transform-duplicate-keys': 7.18.9(@babel/core@7.22.1) - '@babel/plugin-transform-dynamic-import': 7.22.1(@babel/core@7.22.1) - '@babel/plugin-transform-exponentiation-operator': 7.18.6(@babel/core@7.22.1) - '@babel/plugin-transform-export-namespace-from': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-for-of': 7.21.5(@babel/core@7.22.1) - '@babel/plugin-transform-function-name': 7.18.9(@babel/core@7.22.1) - '@babel/plugin-transform-json-strings': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-literals': 7.18.9(@babel/core@7.22.1) - '@babel/plugin-transform-logical-assignment-operators': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-member-expression-literals': 7.18.6(@babel/core@7.22.1) - '@babel/plugin-transform-modules-amd': 7.20.11(@babel/core@7.22.1) - '@babel/plugin-transform-modules-commonjs': 7.21.5(@babel/core@7.22.1) - '@babel/plugin-transform-modules-systemjs': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-modules-umd': 7.18.6(@babel/core@7.22.1) - '@babel/plugin-transform-named-capturing-groups-regex': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-new-target': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-nullish-coalescing-operator': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-numeric-separator': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-object-rest-spread': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-object-super': 7.18.6(@babel/core@7.22.1) - '@babel/plugin-transform-optional-catch-binding': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-optional-chaining': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-parameters': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-private-methods': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-private-property-in-object': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-property-literals': 7.18.6(@babel/core@7.22.1) - '@babel/plugin-transform-regenerator': 7.21.5(@babel/core@7.22.1) - '@babel/plugin-transform-reserved-words': 7.18.6(@babel/core@7.22.1) - '@babel/plugin-transform-shorthand-properties': 7.18.6(@babel/core@7.22.1) - '@babel/plugin-transform-spread': 7.20.7(@babel/core@7.22.1) - '@babel/plugin-transform-sticky-regex': 7.18.6(@babel/core@7.22.1) - '@babel/plugin-transform-template-literals': 7.18.9(@babel/core@7.22.1) - '@babel/plugin-transform-typeof-symbol': 7.18.9(@babel/core@7.22.1) - '@babel/plugin-transform-unicode-escapes': 7.21.5(@babel/core@7.22.1) - '@babel/plugin-transform-unicode-property-regex': 7.22.3(@babel/core@7.22.1) - '@babel/plugin-transform-unicode-regex': 7.18.6(@babel/core@7.22.1) - '@babel/plugin-transform-unicode-sets-regex': 7.22.3(@babel/core@7.22.1) - '@babel/preset-modules': 0.1.5(@babel/core@7.22.1) - '@babel/types': 7.22.4 - babel-plugin-polyfill-corejs2: 0.4.3(@babel/core@7.22.1) - babel-plugin-polyfill-corejs3: 0.8.1(@babel/core@7.22.1) - babel-plugin-polyfill-regenerator: 0.5.0(@babel/core@7.22.1) - core-js-compat: 3.30.2 - semver: 6.3.0 + '@babel/compat-data': 7.23.5 + '@babel/core': 7.18.9 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-option': 7.23.5 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.18.9) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.18.9) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.18.9) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.18.9) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.18.9) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.18.9) + '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.18.9) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.18.9) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.18.9) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.18.9) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.18.9) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.18.9) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.18.9) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.18.9) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.18.9) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.18.9) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.18.9) + '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-async-generator-functions': 7.23.4(@babel/core@7.18.9) + '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.18.9) + '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.18.9) + '@babel/plugin-transform-classes': 7.23.5(@babel/core@7.18.9) + '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.18.9) + '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.18.9) + '@babel/plugin-transform-for-of': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.18.9) + '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.18.9) + '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-modules-systemjs': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.18.9) + '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.18.9) + '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.18.9) + '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.18.9) + '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.18.9) + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.18.9) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.18.9) + '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.18.9) + '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.18.9) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.18.9) + babel-plugin-polyfill-corejs2: 0.4.6(@babel/core@7.18.9) + babel-plugin-polyfill-corejs3: 0.8.6(@babel/core@7.18.9) + babel-plugin-polyfill-regenerator: 0.5.3(@babel/core@7.18.9) + core-js-compat: 3.33.3 + semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /@babel/preset-modules@0.1.5(@babel/core@7.18.9): - resolution: {integrity: sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==} + /@babel/preset-env@7.23.5(@babel/core@7.23.5): + resolution: {integrity: sha512-0d/uxVD6tFGWXGDSfyMD1p2otoaKmu6+GD+NfAx0tMaH+dxORnp7T9TaVQ6mKyya7iBtCIVxHjWT7MuzzM9z+A==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.21.5 - '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.18.9) - '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.18.9) - '@babel/types': 7.22.4 - esutils: 2.0.3 + '@babel/compat-data': 7.23.5 + '@babel/core': 7.23.5 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-option': 7.23.5 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.5) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.5) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.5) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.5) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.5) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.5) + '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.5) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.5) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.5) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.5) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.5) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.5) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.5) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.5) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.5) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.5) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.23.5) + '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-async-generator-functions': 7.23.4(@babel/core@7.23.5) + '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.5) + '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.23.5) + '@babel/plugin-transform-classes': 7.23.5(@babel/core@7.23.5) + '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.23.5) + '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.23.5) + '@babel/plugin-transform-for-of': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.23.5) + '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.23.5) + '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-modules-systemjs': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.5) + '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.23.5) + '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.23.5) + '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.23.5) + '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.23.5) + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.5) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.5) + '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.23.5) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.23.5) + babel-plugin-polyfill-corejs2: 0.4.6(@babel/core@7.23.5) + babel-plugin-polyfill-corejs3: 0.8.6(@babel/core@7.23.5) + babel-plugin-polyfill-regenerator: 0.5.3(@babel/core@7.23.5) + core-js-compat: 3.33.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color dev: true /@babel/preset-modules@0.1.5(@babel/core@7.22.1): @@ -4159,10 +4705,32 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.1 - '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.22.1) - '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.22.1) - '@babel/types': 7.22.4 + '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.22.1) + '@babel/types': 7.23.5 + esutils: 2.0.3 + dev: true + + /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.18.9): + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.18.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/types': 7.23.5 + esutils: 2.0.3 + dev: true + + /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.23.5): + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/types': 7.23.5 esutils: 2.0.3 dev: true @@ -4181,18 +4749,19 @@ packages: '@babel/plugin-transform-react-pure-annotations': 7.18.6(@babel/core@7.18.9) dev: true - /@babel/preset-typescript@7.18.6(@babel/core@7.18.9): - resolution: {integrity: sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==} + /@babel/preset-react@7.22.3(@babel/core@7.23.6): + resolution: {integrity: sha512-lxDz1mnZ9polqClBCVBjIVUypoB4qV3/tZUDb/IlYbW1kiiLaXaX+bInbRjl+lNQ/iUZraQ3+S8daEmoELMWug==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-plugin-utils': 7.19.0 - '@babel/helper-validator-option': 7.18.6 - '@babel/plugin-transform-typescript': 7.20.13(@babel/core@7.18.9) - transitivePeerDependencies: - - supports-color + '@babel/core': 7.23.6 + '@babel/helper-plugin-utils': 7.21.5 + '@babel/helper-validator-option': 7.21.0 + '@babel/plugin-transform-react-display-name': 7.18.6(@babel/core@7.23.6) + '@babel/plugin-transform-react-jsx': 7.22.3(@babel/core@7.23.6) + '@babel/plugin-transform-react-jsx-development': 7.18.6(@babel/core@7.23.6) + '@babel/plugin-transform-react-pure-annotations': 7.18.6(@babel/core@7.23.6) dev: true /@babel/preset-typescript@7.18.6(@babel/core@7.22.1): @@ -4205,8 +4774,18 @@ packages: '@babel/helper-plugin-utils': 7.19.0 '@babel/helper-validator-option': 7.18.6 '@babel/plugin-transform-typescript': 7.20.13(@babel/core@7.22.1) - transitivePeerDependencies: - - supports-color + dev: true + + /@babel/preset-typescript@7.18.6(@babel/core@7.23.6): + resolution: {integrity: sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.6 + '@babel/helper-plugin-utils': 7.19.0 + '@babel/helper-validator-option': 7.18.6 + '@babel/plugin-transform-typescript': 7.20.13(@babel/core@7.23.6) dev: true /@babel/preset-typescript@7.21.5(@babel/core@7.18.9): @@ -4221,22 +4800,12 @@ packages: '@babel/plugin-syntax-jsx': 7.21.4(@babel/core@7.18.9) '@babel/plugin-transform-modules-commonjs': 7.21.5(@babel/core@7.18.9) '@babel/plugin-transform-typescript': 7.22.3(@babel/core@7.18.9) - transitivePeerDependencies: - - supports-color dev: true /@babel/regjsgen@0.8.0: resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} dev: true - /@babel/runtime-corejs3@7.19.6: - resolution: {integrity: sha512-oWNn1ZlGde7b4i/3tnixpH9qI0bOAACiUs+KEES4UUCnsPjVWFlWdLV/iwJuPC2qp3EowbAqsm+0XqNwnwYhxA==} - engines: {node: '>=6.9.0'} - dependencies: - core-js-pure: 3.26.0 - regenerator-runtime: 0.13.10 - dev: true - /@babel/runtime@7.18.9: resolution: {integrity: sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==} engines: {node: '>=6.9.0'} @@ -4250,6 +4819,13 @@ packages: dependencies: regenerator-runtime: 0.13.10 + /@babel/runtime@7.23.6: + resolution: {integrity: sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.0 + dev: true + /@babel/template@7.18.10: resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==} engines: {node: '>=6.9.0'} @@ -4263,17 +4839,17 @@ packages: resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.21.4 - '@babel/parser': 7.22.4 - '@babel/types': 7.22.4 + '@babel/code-frame': 7.23.5 + '@babel/parser': 7.23.5 + '@babel/types': 7.23.5 - /@babel/template@7.21.9: - resolution: {integrity: sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ==} + /@babel/template@7.22.15: + resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.21.4 - '@babel/parser': 7.22.4 - '@babel/types': 7.22.4 + '@babel/code-frame': 7.23.5 + '@babel/parser': 7.23.5 + '@babel/types': 7.23.5 /@babel/traverse@7.19.6: resolution: {integrity: sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==} @@ -4297,35 +4873,53 @@ packages: resolution: {integrity: sha512-AhQoI3YjWi6u/y/ntv7k48mcrCXmus0t79J9qPNlk/lAsFlCiJ047RmbfMOawySTHtywXhbXgpx/8nXMYd+oFw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.21.4 - '@babel/generator': 7.22.3 - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-function-name': 7.21.0 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.22.4 - '@babel/types': 7.22.4 + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.5 + '@babel/types': 7.23.5 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color - /@babel/traverse@7.22.4: - resolution: {integrity: sha512-Tn1pDsjIcI+JcLKq1AVlZEr4226gpuAQTsLMorsYg9tuS/kG7nuwwJ4AB8jfQuEgb/COBwR/DqJxmoiYFu5/rQ==} + /@babel/traverse@7.23.5: + resolution: {integrity: sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.21.4 - '@babel/generator': 7.22.3 - '@babel/helper-environment-visitor': 7.22.1 - '@babel/helper-function-name': 7.21.0 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.22.4 - '@babel/types': 7.22.4 + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.5 + '@babel/types': 7.23.5 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + /@babel/traverse@7.23.6: + resolution: {integrity: sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.6 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.6 + '@babel/types': 7.23.6 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color + dev: true /@babel/types@7.19.4: resolution: {integrity: sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==} @@ -4340,17 +4934,35 @@ packages: resolution: {integrity: sha512-m4AfNvVF2mVC/F7fDEdH2El3HzUg9It/XsCxZiOTTA3m3qYfcSVSbTfM6Q9xG+hYDniZssYhlXKKUMD5m8tF4Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.21.5 - '@babel/helper-validator-identifier': 7.19.1 + '@babel/helper-string-parser': 7.23.4 + '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 /@babel/types@7.22.4: resolution: {integrity: sha512-Tx9x3UBHTTsMSW85WB2kphxYQVvrZ/t1FxD88IpSgIjiUJlCm9z+xWIDwyo1vffTwSqteqyznB8ZE9vYYk16zA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.21.5 - '@babel/helper-validator-identifier': 7.19.1 + '@babel/helper-string-parser': 7.23.4 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + dev: true + + /@babel/types@7.23.5: + resolution: {integrity: sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.23.4 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + + /@babel/types@7.23.6: + resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.23.4 + '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 + dev: true /@bcoe/v8-coverage@0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -4387,35 +4999,17 @@ packages: resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} dev: true - /@esbuild/android-arm64@0.17.19: - resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm64@0.17.7: - resolution: {integrity: sha512-fOUBZvcbtbQJIj2K/LMKcjULGfXLV9R4qjXFsi3UuqFhIRJHz0Fp6kFjsMFI6vLuPrfC5G9Dmh+3RZOrSKY2Lg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm@0.17.19: - resolution: {integrity: sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==} + /@esbuild/android-arm64@0.19.9: + resolution: {integrity: sha512-q4cR+6ZD0938R19MyEW3jEsMzbb/1rulLXiNAJQADD/XYp7pT+rOS5JGxvpRW8dFDEfjW4wLgC/3FXIw4zYglQ==} engines: {node: '>=12'} - cpu: [arm] + cpu: [arm64] os: [android] requiresBuild: true dev: true optional: true - /@esbuild/android-arm@0.17.7: - resolution: {integrity: sha512-Np6Lg8VUiuzHP5XvHU7zfSVPN4ILdiOhxA1GQ1uvCK2T2l3nI8igQV0c9FJx4hTkq8WGqhGEvn5UuRH8jMkExg==} + /@esbuild/android-arm@0.19.9: + resolution: {integrity: sha512-jkYjjq7SdsWuNI6b5quymW0oC83NN5FdRPuCbs9HZ02mfVdAP8B8eeqLSYU3gb6OJEaY5CQabtTFbqBf26H3GA==} engines: {node: '>=12'} cpu: [arm] os: [android] @@ -4423,17 +5017,8 @@ packages: dev: true optional: true - /@esbuild/android-x64@0.17.19: - resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-x64@0.17.7: - resolution: {integrity: sha512-6YILpPvop1rPAvaO/n2iWQL45RyTVTR/1SK7P6Xi2fyu+hpEeX22fE2U2oJd1sfpovUJOWTRdugjddX6QCup3A==} + /@esbuild/android-x64@0.19.9: + resolution: {integrity: sha512-KOqoPntWAH6ZxDwx1D6mRntIgZh9KodzgNOy5Ebt9ghzffOk9X2c1sPwtM9P+0eXbefnDhqYfkh5PLP5ULtWFA==} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -4441,17 +5026,8 @@ packages: dev: true optional: true - /@esbuild/darwin-arm64@0.17.19: - resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-arm64@0.17.7: - resolution: {integrity: sha512-7i0gfFsDt1BBiurZz5oZIpzfxqy5QkJmhXdtrf2Hma/gI9vL2AqxHhRBoI1NeWc9IhN1qOzWZrslhiXZweMSFg==} + /@esbuild/darwin-arm64@0.19.9: + resolution: {integrity: sha512-KBJ9S0AFyLVx2E5D8W0vExqRW01WqRtczUZ8NRu+Pi+87opZn5tL4Y0xT0mA4FtHctd0ZgwNoN639fUUGlNIWw==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] @@ -4459,17 +5035,8 @@ packages: dev: true optional: true - /@esbuild/darwin-x64@0.17.19: - resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-x64@0.17.7: - resolution: {integrity: sha512-hRvIu3vuVIcv4SJXEKOHVsNssM5tLE2xWdb9ZyJqsgYp+onRa5El3VJ4+WjTbkf/A2FD5wuMIbO2FCTV39LE0w==} + /@esbuild/darwin-x64@0.19.9: + resolution: {integrity: sha512-vE0VotmNTQaTdX0Q9dOHmMTao6ObjyPm58CHZr1UK7qpNleQyxlFlNCaHsHx6Uqv86VgPmR4o2wdNq3dP1qyDQ==} engines: {node: '>=12'} cpu: [x64] os: [darwin] @@ -4477,8 +5044,8 @@ packages: dev: true optional: true - /@esbuild/freebsd-arm64@0.17.19: - resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==} + /@esbuild/freebsd-arm64@0.19.9: + resolution: {integrity: sha512-uFQyd/o1IjiEk3rUHSwUKkqZwqdvuD8GevWF065eqgYfexcVkxh+IJgwTaGZVu59XczZGcN/YMh9uF1fWD8j1g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] @@ -4486,26 +5053,8 @@ packages: dev: true optional: true - /@esbuild/freebsd-arm64@0.17.7: - resolution: {integrity: sha512-2NJjeQ9kiabJkVXLM3sHkySqkL1KY8BeyLams3ITyiLW10IwDL0msU5Lq1cULCn9zNxt1Seh1I6QrqyHUvOtQw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-x64@0.17.19: - resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-x64@0.17.7: - resolution: {integrity: sha512-8kSxlbjuLYMoIgvRxPybirHJeW45dflyIgHVs+jzMYJf87QOay1ZUTzKjNL3vqHQjmkSn8p6KDfHVrztn7Rprw==} + /@esbuild/freebsd-x64@0.19.9: + resolution: {integrity: sha512-WMLgWAtkdTbTu1AWacY7uoj/YtHthgqrqhf1OaEWnZb7PQgpt8eaA/F3LkV0E6K/Lc0cUr/uaVP/49iE4M4asA==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] @@ -4513,17 +5062,8 @@ packages: dev: true optional: true - /@esbuild/linux-arm64@0.17.19: - resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm64@0.17.7: - resolution: {integrity: sha512-43Bbhq3Ia/mGFTCRA4NlY8VRH3dLQltJ4cqzhSfq+cdvdm9nKJXVh4NUkJvdZgEZIkf/ufeMmJ0/22v9btXTcw==} + /@esbuild/linux-arm64@0.19.9: + resolution: {integrity: sha512-PiPblfe1BjK7WDAKR1Cr9O7VVPqVNpwFcPWgfn4xu0eMemzRp442hXyzF/fSwgrufI66FpHOEJk0yYdPInsmyQ==} engines: {node: '>=12'} cpu: [arm64] os: [linux] @@ -4531,17 +5071,8 @@ packages: dev: true optional: true - /@esbuild/linux-arm@0.17.19: - resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm@0.17.7: - resolution: {integrity: sha512-07RsAAzznWqdfJC+h3L2UVWwnUHepsFw5GmzySnUspHHb7glJ1+47rvlcH0SeUtoVOs8hF4/THgZbtJRyALaJA==} + /@esbuild/linux-arm@0.19.9: + resolution: {integrity: sha512-C/ChPohUYoyUaqn1h17m/6yt6OB14hbXvT8EgM1ZWaiiTYz7nWZR0SYmMnB5BzQA4GXl3BgBO1l8MYqL/He3qw==} engines: {node: '>=12'} cpu: [arm] os: [linux] @@ -4549,17 +5080,8 @@ packages: dev: true optional: true - /@esbuild/linux-ia32@0.17.19: - resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ia32@0.17.7: - resolution: {integrity: sha512-ViYkfcfnbwOoTS7xE4DvYFv7QOlW8kPBuccc4erJ0jx2mXDPR7e0lYOH9JelotS9qe8uJ0s2i3UjUvjunEp53A==} + /@esbuild/linux-ia32@0.19.9: + resolution: {integrity: sha512-f37i/0zE0MjDxijkPSQw1CO/7C27Eojqb+r3BbHVxMLkj8GCa78TrBZzvPyA/FNLUMzP3eyHCVkAopkKVja+6Q==} engines: {node: '>=12'} cpu: [ia32] os: [linux] @@ -4567,17 +5089,8 @@ packages: dev: true optional: true - /@esbuild/linux-loong64@0.17.19: - resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-loong64@0.17.7: - resolution: {integrity: sha512-H1g+AwwcqYQ/Hl/sMcopRcNLY/fysIb/ksDfCa3/kOaHQNhBrLeDYw+88VAFV5U6oJL9GqnmUj72m9Nv3th3hA==} + /@esbuild/linux-loong64@0.19.9: + resolution: {integrity: sha512-t6mN147pUIf3t6wUt3FeumoOTPfmv9Cc6DQlsVBpB7eCpLOqQDyWBP1ymXn1lDw4fNUSb/gBcKAmvTP49oIkaA==} engines: {node: '>=12'} cpu: [loong64] os: [linux] @@ -4585,17 +5098,8 @@ packages: dev: true optional: true - /@esbuild/linux-mips64el@0.17.19: - resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-mips64el@0.17.7: - resolution: {integrity: sha512-MDLGrVbTGYtmldlbcxfeDPdhxttUmWoX3ovk9u6jc8iM+ueBAFlaXKuUMCoyP/zfOJb+KElB61eSdBPSvNcCEg==} + /@esbuild/linux-mips64el@0.19.9: + resolution: {integrity: sha512-jg9fujJTNTQBuDXdmAg1eeJUL4Jds7BklOTkkH80ZgQIoCTdQrDaHYgbFZyeTq8zbY+axgptncko3v9p5hLZtw==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] @@ -4603,17 +5107,8 @@ packages: dev: true optional: true - /@esbuild/linux-ppc64@0.17.19: - resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ppc64@0.17.7: - resolution: {integrity: sha512-UWtLhRPKzI+v2bKk4j9rBpGyXbLAXLCOeqt1tLVAt1mfagHpFjUzzIHCpPiUfY3x1xY5e45/+BWzGpqqvSglNw==} + /@esbuild/linux-ppc64@0.19.9: + resolution: {integrity: sha512-tkV0xUX0pUUgY4ha7z5BbDS85uI7ABw3V1d0RNTii7E9lbmV8Z37Pup2tsLV46SQWzjOeyDi1Q7Wx2+QM8WaCQ==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] @@ -4621,8 +5116,8 @@ packages: dev: true optional: true - /@esbuild/linux-riscv64@0.17.19: - resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==} + /@esbuild/linux-riscv64@0.19.9: + resolution: {integrity: sha512-DfLp8dj91cufgPZDXr9p3FoR++m3ZJ6uIXsXrIvJdOjXVREtXuQCjfMfvmc3LScAVmLjcfloyVtpn43D56JFHg==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] @@ -4630,26 +5125,8 @@ packages: dev: true optional: true - /@esbuild/linux-riscv64@0.17.7: - resolution: {integrity: sha512-3C/RTKqZauUwBYtIQAv7ELTJd+H2dNKPyzwE2ZTbz2RNrNhNHRoeKnG5C++eM6nSZWUCLyyaWfq1v1YRwBS/+A==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-s390x@0.17.19: - resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-s390x@0.17.7: - resolution: {integrity: sha512-x7cuRSCm998KFZqGEtSo8rI5hXLxWji4znZkBhg2FPF8A8lxLLCsSXe2P5utf0RBQflb3K97dkEH/BJwTqrbDw==} + /@esbuild/linux-s390x@0.19.9: + resolution: {integrity: sha512-zHbglfEdC88KMgCWpOl/zc6dDYJvWGLiUtmPRsr1OgCViu3z5GncvNVdf+6/56O2Ca8jUU+t1BW261V6kp8qdw==} engines: {node: '>=12'} cpu: [s390x] os: [linux] @@ -4657,17 +5134,8 @@ packages: dev: true optional: true - /@esbuild/linux-x64@0.17.19: - resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-x64@0.17.7: - resolution: {integrity: sha512-1Z2BtWgM0Wc92WWiZR5kZ5eC+IetI++X+nf9NMbUvVymt74fnQqwgM5btlTW7P5uCHfq03u5MWHjIZa4o+TnXQ==} + /@esbuild/linux-x64@0.19.9: + resolution: {integrity: sha512-JUjpystGFFmNrEHQnIVG8hKwvA2DN5o7RqiO1CVX8EN/F/gkCjkUMgVn6hzScpwnJtl2mPR6I9XV1oW8k9O+0A==} engines: {node: '>=12'} cpu: [x64] os: [linux] @@ -4675,17 +5143,8 @@ packages: dev: true optional: true - /@esbuild/netbsd-x64@0.17.19: - resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/netbsd-x64@0.17.7: - resolution: {integrity: sha512-//VShPN4hgbmkDjYNCZermIhj8ORqoPNmAnwSPqPtBB0xOpHrXMlJhsqLNsgoBm0zi/5tmy//WyL6g81Uq2c6Q==} + /@esbuild/netbsd-x64@0.19.9: + resolution: {integrity: sha512-GThgZPAwOBOsheA2RUlW5UeroRfESwMq/guy8uEe3wJlAOjpOXuSevLRd70NZ37ZrpO6RHGHgEHvPg1h3S1Jug==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -4693,17 +5152,8 @@ packages: dev: true optional: true - /@esbuild/openbsd-x64@0.17.19: - resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openbsd-x64@0.17.7: - resolution: {integrity: sha512-IQ8BliXHiOsbQEOHzc7mVLIw2UYPpbOXJQ9cK1nClNYQjZthvfiA6rWZMz4BZpVzHZJ+/H2H23cZwRJ1NPYOGg==} + /@esbuild/openbsd-x64@0.19.9: + resolution: {integrity: sha512-Ki6PlzppaFVbLnD8PtlVQfsYw4S9n3eQl87cqgeIw+O3sRr9IghpfSKY62mggdt1yCSZ8QWvTZ9jo9fjDSg9uw==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] @@ -4711,17 +5161,8 @@ packages: dev: true optional: true - /@esbuild/sunos-x64@0.17.19: - resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /@esbuild/sunos-x64@0.17.7: - resolution: {integrity: sha512-phO5HvU3SyURmcW6dfQXX4UEkFREUwaoiTgi1xH+CAFKPGsrcG6oDp1U70yQf5lxRKujoSCEIoBr0uFykJzN2g==} + /@esbuild/sunos-x64@0.19.9: + resolution: {integrity: sha512-MLHj7k9hWh4y1ddkBpvRj2b9NCBhfgBt3VpWbHQnXRedVun/hC7sIyTGDGTfsGuXo4ebik2+3ShjcPbhtFwWDw==} engines: {node: '>=12'} cpu: [x64] os: [sunos] @@ -4729,17 +5170,8 @@ packages: dev: true optional: true - /@esbuild/win32-arm64@0.17.19: - resolution: {integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-arm64@0.17.7: - resolution: {integrity: sha512-G/cRKlYrwp1B0uvzEdnFPJ3A6zSWjnsRrWivsEW0IEHZk+czv0Bmiwa51RncruHLjQ4fGsvlYPmCmwzmutPzHA==} + /@esbuild/win32-arm64@0.19.9: + resolution: {integrity: sha512-GQoa6OrQ8G08guMFgeXPH7yE/8Dt0IfOGWJSfSH4uafwdC7rWwrfE6P9N8AtPGIjUzdo2+7bN8Xo3qC578olhg==} engines: {node: '>=12'} cpu: [arm64] os: [win32] @@ -4747,17 +5179,8 @@ packages: dev: true optional: true - /@esbuild/win32-ia32@0.17.19: - resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-ia32@0.17.7: - resolution: {integrity: sha512-/yMNVlMew07NrOflJdRAZcMdUoYTOCPbCHx0eHtg55l87wXeuhvYOPBQy5HLX31Ku+W2XsBD5HnjUjEUsTXJug==} + /@esbuild/win32-ia32@0.19.9: + resolution: {integrity: sha512-UOozV7Ntykvr5tSOlGCrqU3NBr3d8JqPes0QWN2WOXfvkWVGRajC+Ym0/Wj88fUgecUCLDdJPDF0Nna2UK3Qtg==} engines: {node: '>=12'} cpu: [ia32] os: [win32] @@ -4765,8 +5188,8 @@ packages: dev: true optional: true - /@esbuild/win32-x64@0.17.19: - resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==} + /@esbuild/win32-x64@0.19.9: + resolution: {integrity: sha512-oxoQgglOP7RH6iasDrhY+R/3cHrfwIDvRlT4CGChflq6twk8iENeVvMJjmvBb94Ik1Z+93iGO27err7w6l54GQ==} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -4774,27 +5197,18 @@ packages: dev: true optional: true - /@esbuild/win32-x64@0.17.7: - resolution: {integrity: sha512-K9/YybM6WZO71x73Iyab6mwieHtHjm9hrPR/a9FBPZmFO3w+fJaM2uu2rt3JYf/rZR24MFwTliI8VSoKKOtYtg==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@eslint-community/eslint-utils@4.4.0(eslint@8.48.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.55.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.48.0 + eslint: 8.55.0 eslint-visitor-keys: 3.4.3 dev: true - /@eslint-community/regexpp@4.8.0: - resolution: {integrity: sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==} + /@eslint-community/regexpp@4.10.0: + resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true @@ -4805,7 +5219,7 @@ packages: ajv: 6.12.6 debug: 4.3.4 espree: 7.3.1 - globals: 13.17.0 + globals: 13.21.0 ignore: 4.0.6 import-fresh: 3.3.0 js-yaml: 3.14.1 @@ -4822,7 +5236,7 @@ packages: ajv: 6.12.6 debug: 4.3.4 espree: 9.4.0 - globals: 13.17.0 + globals: 13.21.0 ignore: 5.2.0 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -4832,15 +5246,15 @@ packages: - supports-color dev: true - /@eslint/eslintrc@2.1.2: - resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} + /@eslint/eslintrc@2.1.4: + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 debug: 4.3.4 espree: 9.6.1 - globals: 13.21.0 - ignore: 5.2.4 + globals: 13.24.0 + ignore: 5.3.0 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -4849,8 +5263,8 @@ packages: - supports-color dev: true - /@eslint/js@8.48.0: - resolution: {integrity: sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==} + /@eslint/js@8.55.0: + resolution: {integrity: sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -4877,11 +5291,11 @@ packages: dependencies: react: 18.2.0 - /@humanwhocodes/config-array@0.11.11: - resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} + /@humanwhocodes/config-array@0.11.13: + resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} dependencies: - '@humanwhocodes/object-schema': 1.2.1 + '@humanwhocodes/object-schema': 2.0.1 debug: 4.3.4 minimatch: 3.1.2 transitivePeerDependencies: @@ -4919,6 +5333,22 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true + /@humanwhocodes/object-schema@2.0.1: + resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + dev: true + + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: false + /@istanbuljs/load-nyc-config@1.1.0: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -4949,6 +5379,7 @@ packages: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.19 + dev: true /@jridgewell/gen-mapping@0.3.3: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} @@ -4958,14 +5389,9 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.19 - /@jridgewell/resolve-uri@3.1.0: - resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} - engines: {node: '>=6.0.0'} - /@jridgewell/resolve-uri@3.1.1: resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} engines: {node: '>=6.0.0'} - dev: true /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} @@ -4982,26 +5408,24 @@ packages: resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} dependencies: '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.19 + '@jridgewell/trace-mapping': 0.3.20 dev: true - /@jridgewell/sourcemap-codec@1.4.14: - resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} - /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - /@jridgewell/trace-mapping@0.3.17: - resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} - dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 - /@jridgewell/trace-mapping@0.3.19: resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} dependencies: - '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + + /@jridgewell/trace-mapping@0.3.20: + resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 + dev: true /@jridgewell/trace-mapping@0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} @@ -5040,13 +5464,13 @@ packages: resolution: {integrity: sha512-NhxUZokEq12RLpDo4v/f59dB9A/1BbLgGLFotnrDzNBHfylm0qXSIIel68pZOXUB5lVdPJHqZWcT2zxbpGW6fA==} engines: {node: ^12.16.0 || >=13.7.0} dependencies: - '@babel/core': 7.22.1 - '@babel/generator': 7.22.3 - '@babel/plugin-proposal-export-namespace-from': 7.18.9(@babel/core@7.22.1) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-transform-modules-commonjs': 7.21.5(@babel/core@7.22.1) - '@babel/template': 7.20.7 - '@babel/traverse': 7.21.5 + '@babel/core': 7.18.9 + '@babel/generator': 7.23.5 + '@babel/plugin-proposal-export-namespace-from': 7.18.9(@babel/core@7.18.9) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.18.9) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.18.9) + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.5 '@linaria/core': 3.0.0-beta.22 '@linaria/logger': 3.0.0-beta.20 '@linaria/utils': 3.0.0-beta.20 @@ -5058,25 +5482,26 @@ packages: - supports-color dev: true - /@linaria/babel-preset@4.4.5: - resolution: {integrity: sha512-EqZeVDJrMomjSW/8Soo5ToprM9uYQbpRu8EwTqalwc4+l7anqKuHN9UfzO/Li9O8R+HJ1Lh1ywCoSulxpj268g==} - engines: {node: ^12.16.0 || >=13.7.0} - dependencies: - '@babel/core': 7.22.1 - '@babel/generator': 7.22.3 - '@babel/helper-module-imports': 7.21.4 - '@babel/template': 7.21.9 - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 - '@linaria/core': 4.2.10 - '@linaria/logger': 4.0.0 - '@linaria/shaker': 4.2.11 - '@linaria/tags': 4.3.5 - '@linaria/utils': 4.3.4 + /@linaria/babel-preset@5.0.4: + resolution: {integrity: sha512-OMhlD6gc/+6DFLkadoavlxCtTIElo/UdDMeQH6I/CAL3hgfmHyIXJPrGObTa7jvQKddUaKvFIHGAVB7pz6J8Qg==} + engines: {node: '>=16.0.0'} + dependencies: + '@babel/core': 7.23.5 + '@babel/generator': 7.23.5 + '@babel/helper-module-imports': 7.22.15 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.5 + '@babel/types': 7.23.5 + '@linaria/core': 5.0.2 + '@linaria/logger': 5.0.0 + '@linaria/shaker': 5.0.3 + '@linaria/tags': 5.0.2 + '@linaria/utils': 5.0.2 cosmiconfig: 8.1.3 - find-up: 5.0.0 + happy-dom: 10.8.0 source-map: 0.7.4 stylis: 3.5.4 + ts-invariant: 0.10.3 transitivePeerDependencies: - supports-color dev: true @@ -5091,13 +5516,13 @@ packages: - supports-color dev: true - /@linaria/core@4.2.10: - resolution: {integrity: sha512-S1W01W7L4SQnGpWzp8awyCpPIYUOEJ+OLjjXqKpIXOU+ozPwBt86Mjjdas9aZccVhNBWDja74cMCUAVp8yUpDQ==} - engines: {node: ^12.16.0 || >=13.7.0} + /@linaria/core@5.0.2: + resolution: {integrity: sha512-l5jQq7w9kDvonfr/0MBF47Dagx9Y9f/o5Q8j3zv7GepwG/yHQdbjKr0tq07rx2fSDDX7Nbqlxk6k9Ymir/NGpg==} + engines: {node: '>=16.0.0'} dependencies: - '@linaria/logger': 4.0.0 - '@linaria/tags': 4.3.5 - '@linaria/utils': 4.3.4 + '@linaria/logger': 5.0.0 + '@linaria/tags': 5.0.2 + '@linaria/utils': 5.0.2 transitivePeerDependencies: - supports-color dev: true @@ -5113,30 +5538,16 @@ packages: - supports-color dev: true - /@linaria/esbuild@4.2.11(esbuild@0.17.19): - resolution: {integrity: sha512-kSJTlu3BxfXZikkfo1Dy+F2FCd5Qg/YuUl9S+TnO8QFPfLnm0Np0cnHksvqACq/E7kRbB79/MgpbVLumdNsDHQ==} - engines: {node: ^12.16.0 || >=13.7.0} - peerDependencies: - esbuild: '>=0.12.0' - dependencies: - '@babel/core': 7.22.1 - '@linaria/babel-preset': 4.4.5 - '@linaria/utils': 4.3.4 - esbuild: 0.17.19 - transitivePeerDependencies: - - supports-color - dev: true - - /@linaria/esbuild@4.2.11(esbuild@0.17.7): - resolution: {integrity: sha512-kSJTlu3BxfXZikkfo1Dy+F2FCd5Qg/YuUl9S+TnO8QFPfLnm0Np0cnHksvqACq/E7kRbB79/MgpbVLumdNsDHQ==} - engines: {node: ^12.16.0 || >=13.7.0} + /@linaria/esbuild@5.0.4(esbuild@0.19.9): + resolution: {integrity: sha512-sIPxeH3TQrIfNBz3wCtxTcu/M5dS2SOBSFps+3EVz1LOkIdy5YAOSWL1i1KWUavSg1cs467Ujxq9Nu79k1SayQ==} + engines: {node: '>=16.0.0'} peerDependencies: esbuild: '>=0.12.0' dependencies: - '@babel/core': 7.22.1 - '@linaria/babel-preset': 4.4.5 - '@linaria/utils': 4.3.4 - esbuild: 0.17.7 + '@babel/core': 7.23.5 + '@linaria/babel-preset': 5.0.4 + '@linaria/utils': 5.0.2 + esbuild: 0.19.9 transitivePeerDependencies: - supports-color dev: true @@ -5151,9 +5562,9 @@ packages: - supports-color dev: true - /@linaria/logger@4.0.0: - resolution: {integrity: sha512-YnBq0JlDWMEkTOK+tMo5yEVR0f5V//6qMLToGcLhTyM9g9i+IDFn51Z+5q2hLk7RdG4NBPgbcCXYi2w4RKsPeg==} - engines: {node: ^12.16.0 || >=13.7.0} + /@linaria/logger@5.0.0: + resolution: {integrity: sha512-PZd5H0I4F84U0kXSE+vD75ltIGDxEA6gMDNWS2aDZFitmdlQM5rIXqvKFrp5NsHa7a3AH+I2Hxm0dg60WZF7vg==} + engines: {node: '>=16.0.0'} dependencies: debug: 4.3.4 picocolors: 1.0.0 @@ -5184,16 +5595,17 @@ packages: - supports-color dev: true - /@linaria/react@4.3.8(react@18.2.0): - resolution: {integrity: sha512-+Io4PXXyopxiSemk+5QdyqF4+uJJwVUx9yIhUrVJhKluwyJ0KsNA00gY+d5wpT5FhTsnVpv4Ef3YEcPHcVUuow==} - engines: {node: ^12.16.0 || >=13.7.0} + /@linaria/react@5.0.3(react@18.2.0): + resolution: {integrity: sha512-faTQHnUlrAz0Lodu+rr6Yx59rX0nqFOrZ5/IdlfQcTRz9VebyVL4vtA3AOecmn1YFZjMpqjopT0OzNz6GknQSg==} + engines: {node: '>=16.0.0'} peerDependencies: react: '>=16' dependencies: '@emotion/is-prop-valid': 1.2.1 - '@linaria/core': 4.2.10 - '@linaria/tags': 4.3.5 - '@linaria/utils': 4.3.4 + '@linaria/core': 5.0.2 + '@linaria/tags': 5.0.2 + '@linaria/utils': 5.0.2 + minimatch: 9.0.3 react: 18.2.0 react-html-attributes: 1.4.6 ts-invariant: 0.10.3 @@ -5206,10 +5618,10 @@ packages: engines: {node: ^12.16.0 || >=13.7.0} dependencies: '@babel/core': 7.18.9 - '@babel/generator': 7.19.6 - '@babel/plugin-transform-runtime': 7.19.6(@babel/core@7.18.9) - '@babel/plugin-transform-template-literals': 7.18.9(@babel/core@7.18.9) - '@babel/preset-env': 7.19.4(@babel/core@7.18.9) + '@babel/generator': 7.23.5 + '@babel/plugin-transform-runtime': 7.23.4(@babel/core@7.18.9) + '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.18.9) + '@babel/preset-env': 7.23.5(@babel/core@7.18.9) '@linaria/babel-preset': 3.0.0-beta.22 '@linaria/logger': 3.0.0-beta.20 '@linaria/preeval': 3.0.0-beta.23 @@ -5237,31 +5649,31 @@ packages: - supports-color dev: true - /@linaria/shaker@4.2.11: - resolution: {integrity: sha512-4QEMHoxWI/zH8tjuIa4y3tfrW3bWmRPxNGZ66IdSm19IivWMRxWl+viYHCDn3lL7JQTXn1MURsEopVmUs4p2Lw==} - engines: {node: ^12.16.0 || >=13.7.0} + /@linaria/shaker@5.0.3: + resolution: {integrity: sha512-2a3pzYs09Iz88e+VG4OAQVRSIjxkbj7S4ju81ZTJVbZIWSR1kGsbX5OtJkRrh/AbKRrrUMW0DBS4PPgd0fks4A==} + engines: {node: '>=16.0.0'} dependencies: - '@babel/core': 7.22.1 - '@babel/generator': 7.22.3 - '@babel/plugin-transform-modules-commonjs': 7.21.5(@babel/core@7.22.1) - '@babel/plugin-transform-runtime': 7.19.6(@babel/core@7.22.1) - '@babel/plugin-transform-template-literals': 7.18.9(@babel/core@7.22.1) - '@babel/preset-env': 7.22.4(@babel/core@7.22.1) - '@linaria/logger': 4.0.0 - '@linaria/utils': 4.3.4 + '@babel/core': 7.23.5 + '@babel/generator': 7.23.5 + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.5) + '@babel/plugin-transform-runtime': 7.23.4(@babel/core@7.23.5) + '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.23.5) + '@babel/preset-env': 7.23.5(@babel/core@7.23.5) + '@linaria/logger': 5.0.0 + '@linaria/utils': 5.0.2 babel-plugin-transform-react-remove-prop-types: 0.4.24 ts-invariant: 0.10.3 transitivePeerDependencies: - supports-color dev: true - /@linaria/tags@4.3.5: - resolution: {integrity: sha512-PgaIi8Vv89YOjc6rpKL/uPg2w4k0rAwAYxcqeXqzKqsEAste5rgB8xp1/KUOG0oAOkPd3MRL6Duj+m0ZwJ3g+g==} - engines: {node: ^12.16.0 || >=13.7.0} + /@linaria/tags@5.0.2: + resolution: {integrity: sha512-opcORl2sA6WkBjTNLHTgpet97dNKnwPRX/QGGZMykBsvGH3AsnEg/bT31cKBMBhL+YBGQsCdBmolxvCkWPOXQw==} + engines: {node: '>=16.0.0'} dependencies: - '@babel/generator': 7.22.3 - '@linaria/logger': 4.0.0 - '@linaria/utils': 4.3.4 + '@babel/generator': 7.23.5 + '@linaria/logger': 5.0.0 + '@linaria/utils': 5.0.2 transitivePeerDependencies: - supports-color dev: true @@ -5271,34 +5683,36 @@ packages: engines: {node: ^12.16.0 || >=13.7.0} dev: true - /@linaria/utils@4.3.4: - resolution: {integrity: sha512-vt6WJG54n+KANaqxOfzIIU7aSfFHEWFbnGLsgxL7nASHqO0zezrNA2y2Rrp80zSeTW+wSpbmDM4uJyC9UW1qoA==} - engines: {node: ^12.16.0 || >=13.7.0} + /@linaria/utils@5.0.2: + resolution: {integrity: sha512-ZL8Yz4IIr9A8a5+o5LRnEpgdzIkyj4yKJrhw5Zv8wwvL+d/MHUK0q+l/KvxBmuYdcF+YYVHZ9eeBHTQBSL7r/w==} + engines: {node: '>=16.0.0'} dependencies: - '@babel/core': 7.22.1 - '@babel/plugin-proposal-export-namespace-from': 7.18.9(@babel/core@7.22.1) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.1) - '@babel/plugin-transform-modules-commonjs': 7.21.5(@babel/core@7.22.1) - '@babel/traverse': 7.22.4 - '@babel/types': 7.22.4 - '@linaria/logger': 4.0.0 - babel-merge: 3.0.0(@babel/core@7.22.1) + '@babel/core': 7.23.5 + '@babel/generator': 7.23.5 + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.5) + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.5 + '@babel/types': 7.23.5 + '@linaria/logger': 5.0.0 + babel-merge: 3.0.0(@babel/core@7.23.5) + find-up: 5.0.0 + minimatch: 9.0.3 transitivePeerDependencies: - supports-color dev: true - /@linaria/webpack-loader@3.0.0-beta.22(webpack@4.46.0): + /@linaria/webpack-loader@3.0.0-beta.22(webpack@4.47.0): resolution: {integrity: sha512-oSChk+9MfcoF1M3Thx++aB1IjAaq7gS643i4995GSm1fs53i6QeUpCvIlWClDtRADmBzHSdMKIt0/vLoESvBoQ==} engines: {node: ^12.16.0 || >=13.7.0} dependencies: - '@linaria/webpack4-loader': 3.0.0-beta.23(webpack@4.46.0) - '@linaria/webpack5-loader': 3.0.0-beta.23(webpack@4.46.0) + '@linaria/webpack4-loader': 3.0.0-beta.23(webpack@4.47.0) + '@linaria/webpack5-loader': 3.0.0-beta.23(webpack@4.47.0) transitivePeerDependencies: - supports-color - webpack dev: true - /@linaria/webpack4-loader@3.0.0-beta.23(webpack@4.46.0): + /@linaria/webpack4-loader@3.0.0-beta.23(webpack@4.47.0): resolution: {integrity: sha512-I1pwrRKpGCARWbPwTFqOKLrkyxrZ+huYC3WH4pMllfoY+fv3O2dmDH6vKrZ582mQ5Uo/H3FmHBt8CLaMBv3pmg==} engines: {node: ^12.16.0 || >=13.7.0} peerDependencies: @@ -5309,12 +5723,12 @@ packages: enhanced-resolve: 4.5.0 loader-utils: 1.4.0 mkdirp: 0.5.6 - webpack: 4.46.0 + webpack: 4.47.0 transitivePeerDependencies: - supports-color dev: true - /@linaria/webpack5-loader@3.0.0-beta.23(webpack@4.46.0): + /@linaria/webpack5-loader@3.0.0-beta.23(webpack@4.47.0): resolution: {integrity: sha512-yIjhnDT1otwfx6JAA9HNfDzim7N93z9++8apzXE57GXg5wRO2hlajruatclpUDcMOsodS9p2+mMXd8GGR8CGCA==} engines: {node: ^12.16.0 || >=13.7.0} peerDependencies: @@ -5324,8 +5738,26 @@ packages: '@linaria/logger': 3.0.0-beta.20 enhanced-resolve: 5.10.0 mkdirp: 0.5.6 - webpack: 4.46.0 + webpack: 4.47.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@mapbox/node-pre-gyp@1.0.11: + resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} + hasBin: true + dependencies: + detect-libc: 2.0.2 + https-proxy-agent: 5.0.1 + make-dir: 3.1.0 + node-fetch: 2.7.0 + nopt: 5.0.0 + npmlog: 5.0.1 + rimraf: 3.0.2 + semver: 7.5.4 + tar: 6.2.0 transitivePeerDependencies: + - encoding - supports-color dev: true @@ -5365,7 +5797,7 @@ packages: resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==} dependencies: '@gar/promisify': 1.1.3 - semver: 7.3.8 + semver: 7.5.4 dev: true /@npmcli/move-file@1.1.2: @@ -5376,6 +5808,13 @@ packages: rimraf: 3.0.2 dev: true + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + dev: false + optional: true + /@polka/url@1.0.0-next.21: resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} dev: true @@ -5433,7 +5872,7 @@ packages: optional: true dependencies: '@babel/core': 7.18.9 - '@babel/helper-module-imports': 7.21.4 + '@babel/helper-module-imports': 7.22.15 '@rollup/pluginutils': 3.1.0(rollup@2.79.1) rollup: 2.79.1 dev: true @@ -5449,7 +5888,7 @@ packages: builtin-modules: 3.3.0 deepmerge: 4.2.2 is-module: 1.0.0 - resolve: 1.22.2 + resolve: 1.22.8 rollup: 2.79.1 dev: true @@ -5475,18 +5914,31 @@ packages: rollup: 2.79.1 dev: true + /@rollup/pluginutils@4.2.1: + resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} + engines: {node: '>= 8.0.0'} + dependencies: + estree-walker: 2.0.2 + picomatch: 2.3.1 + dev: true + /@sindresorhus/is@0.14.0: resolution: {integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==} engines: {node: '>=6'} dev: true + /@sindresorhus/merge-streams@1.0.0: + resolution: {integrity: sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw==} + engines: {node: '>=18'} + dev: true + /@surma/rollup-plugin-off-main-thread@2.2.3: resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} dependencies: ejs: 3.1.8 json5: 2.2.3 magic-string: 0.25.9 - string.prototype.matchall: 4.0.7 + string.prototype.matchall: 4.0.10 dev: true /@szmarczak/http-timer@1.1.2: @@ -5538,8 +5990,8 @@ packages: resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==} dev: true - /@types/better-sqlite3@7.6.4: - resolution: {integrity: sha512-dzrRZCYPXIXfSR1/surNbJ/grU3scTaygS0OMzjlGf71i9sc2fGyHPXXiXmEvNIoE0cGwsanEFMVJxPXmco9Eg==} + /@types/better-sqlite3@7.6.8: + resolution: {integrity: sha512-ASndM4rdGrzk7iXXqyNC4fbwt4UEjpK0i3j4q4FyeQrLAthfB6s7EF135ZJE0qQxtKIMFwmyT6x0switET7uIw==} dependencies: '@types/node': 20.4.1 dev: true @@ -5626,8 +6078,8 @@ packages: '@types/node': 18.11.17 dev: true - /@types/istanbul-lib-coverage@2.0.4: - resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} + /@types/istanbul-lib-coverage@2.0.6: + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} dev: true /@types/json-schema@7.0.11: @@ -5671,12 +6123,14 @@ packages: /@types/node@18.11.17: resolution: {integrity: sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==} - /@types/node@20.4.1: - resolution: {integrity: sha512-JIzsAvJeA/5iY6Y/OxZbv1lUcc8dNSE77lb2gnBH+/PJ3lFR1Ccvgwl5JWnHAkNHcRsT0TbpVOsiMKZ1F/yyJg==} + /@types/node@20.10.4: + resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} + dependencies: + undici-types: 5.26.5 dev: true - /@types/node@20.5.9: - resolution: {integrity: sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==} + /@types/node@20.4.1: + resolution: {integrity: sha512-JIzsAvJeA/5iY6Y/OxZbv1lUcc8dNSE77lb2gnBH+/PJ3lFR1Ccvgwl5JWnHAkNHcRsT0TbpVOsiMKZ1F/yyJg==} dev: true /@types/parse-json@4.0.0: @@ -5781,7 +6235,7 @@ packages: '@types/node': 18.11.17 dev: true - /@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.2.2): + /@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.3.3): resolution: {integrity: sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -5792,8 +6246,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/experimental-utils': 4.33.0(eslint@7.32.0)(typescript@5.2.2) - '@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.2.2) + '@typescript-eslint/experimental-utils': 4.33.0(eslint@7.32.0)(typescript@5.3.3) + '@typescript-eslint/parser': 4.33.0(eslint@7.32.0)(typescript@5.3.3) '@typescript-eslint/scope-manager': 4.33.0 debug: 4.3.4 eslint: 7.32.0 @@ -5801,13 +6255,13 @@ packages: ignore: 5.2.0 regexpp: 3.2.0 semver: 7.3.8 - tsutils: 3.21.0(typescript@5.2.2) - typescript: 5.2.2 + tsutils: 3.21.0(typescript@5.3.3) + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/eslint-plugin@5.41.0(@typescript-eslint/parser@5.41.0)(eslint@8.26.0)(typescript@5.2.2): + /@typescript-eslint/eslint-plugin@5.41.0(@typescript-eslint/parser@5.41.0)(eslint@8.26.0)(typescript@5.3.3): resolution: {integrity: sha512-DXUS22Y57/LAFSg3x7Vi6RNAuLpTXwxB9S2nIA7msBb/Zt8p7XqMwdpdc1IU7CkOQUPgAqR5fWvxuKCbneKGmA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -5818,22 +6272,22 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.41.0(eslint@8.26.0)(typescript@5.2.2) + '@typescript-eslint/parser': 5.41.0(eslint@8.26.0)(typescript@5.3.3) '@typescript-eslint/scope-manager': 5.41.0 - '@typescript-eslint/type-utils': 5.41.0(eslint@8.26.0)(typescript@5.2.2) - '@typescript-eslint/utils': 5.41.0(eslint@8.26.0)(typescript@5.2.2) + '@typescript-eslint/type-utils': 5.41.0(eslint@8.26.0)(typescript@5.3.3) + '@typescript-eslint/utils': 5.41.0(eslint@8.26.0)(typescript@5.3.3) debug: 4.3.4 eslint: 8.26.0 ignore: 5.2.0 regexpp: 3.2.0 semver: 7.3.8 - tsutils: 3.21.0(typescript@5.2.2) - typescript: 5.2.2 + tsutils: 3.21.0(typescript@5.3.3) + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/eslint-plugin@5.41.0(@typescript-eslint/parser@5.41.0)(eslint@8.48.0)(typescript@5.2.2): + /@typescript-eslint/eslint-plugin@5.41.0(@typescript-eslint/parser@5.41.0)(eslint@8.55.0)(typescript@5.3.3): resolution: {integrity: sha512-DXUS22Y57/LAFSg3x7Vi6RNAuLpTXwxB9S2nIA7msBb/Zt8p7XqMwdpdc1IU7CkOQUPgAqR5fWvxuKCbneKGmA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -5844,22 +6298,22 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.41.0(eslint@8.48.0)(typescript@5.2.2) + '@typescript-eslint/parser': 5.41.0(eslint@8.55.0)(typescript@5.3.3) '@typescript-eslint/scope-manager': 5.41.0 - '@typescript-eslint/type-utils': 5.41.0(eslint@8.48.0)(typescript@5.2.2) - '@typescript-eslint/utils': 5.41.0(eslint@8.48.0)(typescript@5.2.2) + '@typescript-eslint/type-utils': 5.41.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/utils': 5.41.0(eslint@8.55.0)(typescript@5.3.3) debug: 4.3.4 - eslint: 8.48.0 + eslint: 8.55.0 ignore: 5.2.0 regexpp: 3.2.0 semver: 7.3.8 - tsutils: 3.21.0(typescript@5.2.2) - typescript: 5.2.2 + tsutils: 3.21.0(typescript@5.3.3) + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/experimental-utils@4.33.0(eslint@7.32.0)(typescript@5.2.2): + /@typescript-eslint/experimental-utils@4.33.0(eslint@7.32.0)(typescript@5.3.3): resolution: {integrity: sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -5868,7 +6322,7 @@ packages: '@types/json-schema': 7.0.11 '@typescript-eslint/scope-manager': 4.33.0 '@typescript-eslint/types': 4.33.0 - '@typescript-eslint/typescript-estree': 4.33.0(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 4.33.0(typescript@5.3.3) eslint: 7.32.0 eslint-scope: 5.1.1 eslint-utils: 3.0.0(eslint@7.32.0) @@ -5877,33 +6331,33 @@ packages: - typescript dev: true - /@typescript-eslint/experimental-utils@5.41.0(eslint@7.32.0)(typescript@5.2.2): + /@typescript-eslint/experimental-utils@5.41.0(eslint@7.32.0)(typescript@5.3.3): resolution: {integrity: sha512-/qxT2Kd2q/A22JVIllvws4rvc00/3AT4rAo/0YgEN28y+HPhbJbk6X4+MAHEoZzpNyAOugIT7D/OLnKBW8FfhA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/utils': 5.41.0(eslint@7.32.0)(typescript@5.2.2) + '@typescript-eslint/utils': 5.41.0(eslint@7.32.0)(typescript@5.3.3) eslint: 7.32.0 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/experimental-utils@5.41.0(eslint@8.48.0)(typescript@5.2.2): + /@typescript-eslint/experimental-utils@5.41.0(eslint@8.55.0)(typescript@5.3.3): resolution: {integrity: sha512-/qxT2Kd2q/A22JVIllvws4rvc00/3AT4rAo/0YgEN28y+HPhbJbk6X4+MAHEoZzpNyAOugIT7D/OLnKBW8FfhA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/utils': 5.41.0(eslint@8.48.0)(typescript@5.2.2) - eslint: 8.48.0 + '@typescript-eslint/utils': 5.41.0(eslint@8.55.0)(typescript@5.3.3) + eslint: 8.55.0 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.2.2): + /@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.3.3): resolution: {integrity: sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -5915,15 +6369,15 @@ packages: dependencies: '@typescript-eslint/scope-manager': 4.33.0 '@typescript-eslint/types': 4.33.0 - '@typescript-eslint/typescript-estree': 4.33.0(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 4.33.0(typescript@5.3.3) debug: 4.3.4 eslint: 7.32.0 - typescript: 5.2.2 + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@5.41.0(eslint@8.26.0)(typescript@5.2.2): + /@typescript-eslint/parser@5.41.0(eslint@8.26.0)(typescript@5.3.3): resolution: {integrity: sha512-HQVfix4+RL5YRWZboMD1pUfFN8MpRH4laziWkkAzyO1fvNOY/uinZcvo3QiFJVS/siNHupV8E5+xSwQZrl6PZA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -5935,15 +6389,15 @@ packages: dependencies: '@typescript-eslint/scope-manager': 5.41.0 '@typescript-eslint/types': 5.41.0 - '@typescript-eslint/typescript-estree': 5.41.0(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 5.41.0(typescript@5.3.3) debug: 4.3.4 eslint: 8.26.0 - typescript: 5.2.2 + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@5.41.0(eslint@8.48.0)(typescript@5.2.2): + /@typescript-eslint/parser@5.41.0(eslint@8.55.0)(typescript@5.3.3): resolution: {integrity: sha512-HQVfix4+RL5YRWZboMD1pUfFN8MpRH4laziWkkAzyO1fvNOY/uinZcvo3QiFJVS/siNHupV8E5+xSwQZrl6PZA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -5955,10 +6409,10 @@ packages: dependencies: '@typescript-eslint/scope-manager': 5.41.0 '@typescript-eslint/types': 5.41.0 - '@typescript-eslint/typescript-estree': 5.41.0(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 5.41.0(typescript@5.3.3) debug: 4.3.4 - eslint: 8.48.0 - typescript: 5.2.2 + eslint: 8.55.0 + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true @@ -5979,7 +6433,7 @@ packages: '@typescript-eslint/visitor-keys': 5.41.0 dev: true - /@typescript-eslint/type-utils@5.41.0(eslint@8.26.0)(typescript@5.2.2): + /@typescript-eslint/type-utils@5.41.0(eslint@8.26.0)(typescript@5.3.3): resolution: {integrity: sha512-L30HNvIG6A1Q0R58e4hu4h+fZqaO909UcnnPbwKiN6Rc3BUEx6ez2wgN7aC0cBfcAjZfwkzE+E2PQQ9nEuoqfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -5989,17 +6443,17 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.41.0(typescript@5.2.2) - '@typescript-eslint/utils': 5.41.0(eslint@8.26.0)(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 5.41.0(typescript@5.3.3) + '@typescript-eslint/utils': 5.41.0(eslint@8.26.0)(typescript@5.3.3) debug: 4.3.4 eslint: 8.26.0 - tsutils: 3.21.0(typescript@5.2.2) - typescript: 5.2.2 + tsutils: 3.21.0(typescript@5.3.3) + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/type-utils@5.41.0(eslint@8.48.0)(typescript@5.2.2): + /@typescript-eslint/type-utils@5.41.0(eslint@8.55.0)(typescript@5.3.3): resolution: {integrity: sha512-L30HNvIG6A1Q0R58e4hu4h+fZqaO909UcnnPbwKiN6Rc3BUEx6ez2wgN7aC0cBfcAjZfwkzE+E2PQQ9nEuoqfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -6009,12 +6463,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.41.0(typescript@5.2.2) - '@typescript-eslint/utils': 5.41.0(eslint@8.48.0)(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 5.41.0(typescript@5.3.3) + '@typescript-eslint/utils': 5.41.0(eslint@8.55.0)(typescript@5.3.3) debug: 4.3.4 - eslint: 8.48.0 - tsutils: 3.21.0(typescript@5.2.2) - typescript: 5.2.2 + eslint: 8.55.0 + tsutils: 3.21.0(typescript@5.3.3) + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true @@ -6029,7 +6483,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree@4.33.0(typescript@5.2.2): + /@typescript-eslint/typescript-estree@4.33.0(typescript@5.3.3): resolution: {integrity: sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -6044,13 +6498,13 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.3.8 - tsutils: 3.21.0(typescript@5.2.2) - typescript: 5.2.2 + tsutils: 3.21.0(typescript@5.3.3) + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/typescript-estree@5.41.0(typescript@5.2.2): + /@typescript-eslint/typescript-estree@5.41.0(typescript@5.3.3): resolution: {integrity: sha512-SlzFYRwFSvswzDSQ/zPkIWcHv8O5y42YUskko9c4ki+fV6HATsTODUPbRbcGDFYP86gaJL5xohUEytvyNNcXWg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -6065,13 +6519,13 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.3.8 - tsutils: 3.21.0(typescript@5.2.2) - typescript: 5.2.2 + tsutils: 3.21.0(typescript@5.3.3) + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@5.41.0(eslint@7.32.0)(typescript@5.2.2): + /@typescript-eslint/utils@5.41.0(eslint@7.32.0)(typescript@5.3.3): resolution: {integrity: sha512-QlvfwaN9jaMga9EBazQ+5DDx/4sAdqDkcs05AsQHMaopluVCUyu1bTRUVKzXbgjDlrRAQrYVoi/sXJ9fmG+KLQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -6081,7 +6535,7 @@ packages: '@types/semver': 7.3.12 '@typescript-eslint/scope-manager': 5.41.0 '@typescript-eslint/types': 5.41.0 - '@typescript-eslint/typescript-estree': 5.41.0(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 5.41.0(typescript@5.3.3) eslint: 7.32.0 eslint-scope: 5.1.1 eslint-utils: 3.0.0(eslint@7.32.0) @@ -6091,7 +6545,7 @@ packages: - typescript dev: true - /@typescript-eslint/utils@5.41.0(eslint@8.26.0)(typescript@5.2.2): + /@typescript-eslint/utils@5.41.0(eslint@8.26.0)(typescript@5.3.3): resolution: {integrity: sha512-QlvfwaN9jaMga9EBazQ+5DDx/4sAdqDkcs05AsQHMaopluVCUyu1bTRUVKzXbgjDlrRAQrYVoi/sXJ9fmG+KLQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -6101,7 +6555,7 @@ packages: '@types/semver': 7.3.12 '@typescript-eslint/scope-manager': 5.41.0 '@typescript-eslint/types': 5.41.0 - '@typescript-eslint/typescript-estree': 5.41.0(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 5.41.0(typescript@5.3.3) eslint: 8.26.0 eslint-scope: 5.1.1 eslint-utils: 3.0.0(eslint@8.26.0) @@ -6111,7 +6565,7 @@ packages: - typescript dev: true - /@typescript-eslint/utils@5.41.0(eslint@8.48.0)(typescript@5.2.2): + /@typescript-eslint/utils@5.41.0(eslint@8.55.0)(typescript@5.3.3): resolution: {integrity: sha512-QlvfwaN9jaMga9EBazQ+5DDx/4sAdqDkcs05AsQHMaopluVCUyu1bTRUVKzXbgjDlrRAQrYVoi/sXJ9fmG+KLQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -6121,10 +6575,10 @@ packages: '@types/semver': 7.3.12 '@typescript-eslint/scope-manager': 5.41.0 '@typescript-eslint/types': 5.41.0 - '@typescript-eslint/typescript-estree': 5.41.0(typescript@5.2.2) - eslint: 8.48.0 + '@typescript-eslint/typescript-estree': 5.41.0(typescript@5.3.3) + eslint: 8.55.0 eslint-scope: 5.1.1 - eslint-utils: 3.0.0(eslint@8.48.0) + eslint-utils: 3.0.0(eslint@8.55.0) semver: 7.3.8 transitivePeerDependencies: - supports-color @@ -6147,8 +6601,33 @@ packages: eslint-visitor-keys: 3.3.0 dev: true - /@ungap/promise-all-settled@1.1.2: - resolution: {integrity: sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==} + /@ungap/promise-all-settled@1.1.2: + resolution: {integrity: sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==} + dev: true + + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + dev: true + + /@vercel/nft@0.24.4: + resolution: {integrity: sha512-KjYAZty7boH5fi5udp6p+lNu6nawgs++pHW+3koErMgbRkkHuToGX/FwjN5clV1FcaM3udfd4zW/sUapkMgpZw==} + engines: {node: '>=16'} + hasBin: true + dependencies: + '@mapbox/node-pre-gyp': 1.0.11 + '@rollup/pluginutils': 4.2.1 + acorn: 8.11.2 + async-sema: 3.1.1 + bindings: 1.5.0 + estree-walker: 2.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + micromatch: 4.0.5 + node-gyp-build: 4.7.1 + resolve-from: 5.0.0 + transitivePeerDependencies: + - encoding + - supports-color dev: true /@webassemblyjs/ast@1.9.0: @@ -6290,6 +6769,10 @@ packages: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} dev: true + /abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + dev: true + /accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -6313,12 +6796,12 @@ packages: acorn: 7.4.1 dev: true - /acorn-jsx@5.3.2(acorn@8.10.0): + /acorn-jsx@5.3.2(acorn@8.11.2): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.10.0 + acorn: 8.11.2 dev: true /acorn-jsx@5.3.2(acorn@8.8.1): @@ -6339,6 +6822,11 @@ packages: engines: {node: '>=0.4.0'} dev: true + /acorn-walk@8.3.1: + resolution: {integrity: sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==} + engines: {node: '>=0.4.0'} + dev: true + /acorn@6.4.2: resolution: {integrity: sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==} engines: {node: '>=0.4.0'} @@ -6356,6 +6844,12 @@ packages: hasBin: true dev: true + /acorn@8.11.2: + resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /acorn@8.8.1: resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==} engines: {node: '>=0.4.0'} @@ -6367,6 +6861,15 @@ packages: hasBin: true dev: true + /agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -6375,14 +6878,6 @@ packages: indent-string: 4.0.0 dev: true - /aggregate-error@4.0.1: - resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} - engines: {node: '>=12'} - dependencies: - clean-stack: 4.2.0 - indent-string: 5.0.0 - dev: true - /ajv-errors@1.0.1(ajv@6.12.6): resolution: {integrity: sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==} peerDependencies: @@ -6475,12 +6970,10 @@ packages: /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - dev: true /ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} - dev: true /ansi-sequence-parser@1.1.1: resolution: {integrity: sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==} @@ -6502,12 +6995,10 @@ packages: engines: {node: '>=8'} dependencies: color-convert: 2.0.1 - dev: true /ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} - dev: true /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -6541,10 +7032,22 @@ packages: resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} dev: true + /aproba@2.0.0: + resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} + dev: true + /archy@1.0.0: resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} dev: true + /are-we-there-yet@2.0.0: + resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} + engines: {node: '>=10'} + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.2 + dev: true + /arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} dev: true @@ -6562,12 +7065,10 @@ packages: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true - /aria-query@4.2.2: - resolution: {integrity: sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==} - engines: {node: '>=6.0'} + /aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} dependencies: - '@babel/runtime': 7.19.4 - '@babel/runtime-corejs3': 7.19.6 + dequal: 2.0.3 dev: true /arr-diff@4.0.0: @@ -6585,6 +7086,13 @@ packages: engines: {node: '>=0.10.0'} dev: true + /array-buffer-byte-length@1.0.0: + resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + dependencies: + call-bind: 1.0.5 + is-array-buffer: 3.0.2 + dev: true + /array-equal@1.0.0: resolution: {integrity: sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA==} dev: true @@ -6613,6 +7121,17 @@ packages: is-string: 1.0.7 dev: true + /array-includes@3.1.7: + resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + is-string: 1.0.7 + dev: true + /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -6623,14 +7142,25 @@ packages: engines: {node: '>=0.10.0'} dev: true - /array.prototype.flat@1.3.0: - resolution: {integrity: sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==} + /array.prototype.findlastindex@1.2.3: + resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 - es-shim-unscopables: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + get-intrinsic: 1.2.2 + dev: true + + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 dev: true /array.prototype.flatmap@1.3.0: @@ -6643,6 +7173,16 @@ packages: es-shim-unscopables: 1.0.0 dev: true + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + dev: true + /array.prototype.reduce@1.0.4: resolution: {integrity: sha512-WnM+AjG/DvLRLo4DDl+r+SvCzYtD2Jd9oeBYMcEaI7t3fFrHY9M53/wdLcTvmZNQ70IU6Htj0emFkZ5TS+lrdw==} engines: {node: '>= 0.4'} @@ -6654,6 +7194,29 @@ packages: is-string: 1.0.7 dev: true + /array.prototype.tosorted@1.1.2: + resolution: {integrity: sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + get-intrinsic: 1.2.2 + dev: true + + /arraybuffer.prototype.slice@1.0.2: + resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + is-array-buffer: 3.0.2 + is-shared-array-buffer: 1.0.2 + dev: true + /arrgv@1.0.2: resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==} engines: {node: '>=8.0.0'} @@ -6706,8 +7269,8 @@ packages: '@mdn/browser-compat-data': 3.3.14 dev: true - /ast-types-flow@0.0.7: - resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} + /ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} dev: true /astral-regex@2.0.0: @@ -6725,10 +7288,20 @@ packages: resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} dev: true + /async-sema@3.1.1: + resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} + dev: true + /async@3.2.4: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} dev: true + /asynciterator.prototype@1.0.0: + resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} + dependencies: + has-symbols: 1.0.3 + dev: true + /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} dev: true @@ -6760,69 +7333,25 @@ packages: postcss-value-parser: 4.2.0 dev: true - /ava@4.3.3(@ava/typescript@4.0.0): - resolution: {integrity: sha512-9Egq/d9R74ExrWohHeqUlexjDbgZJX5jA1Wq4KCTqc3wIfpGEK79zVy4rBtofJ9YKIxs4PzhJ8BgbW5PlAYe6w==} - engines: {node: '>=12.22 <13 || >=14.17 <15 || >=16.4 <17 || >=18'} + /autoprefixer@10.4.14(postcss@8.4.32): + resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} + engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: - '@ava/typescript': '*' - peerDependenciesMeta: - '@ava/typescript': - optional: true + postcss: ^8.1.0 dependencies: - '@ava/typescript': 4.0.0 - acorn: 8.8.1 - acorn-walk: 8.2.0 - ansi-styles: 6.2.1 - arrgv: 1.0.2 - arrify: 3.0.0 - callsites: 4.0.0 - cbor: 8.1.0 - chalk: 5.1.2 - chokidar: 3.5.3 - chunkd: 2.0.1 - ci-info: 3.5.0 - ci-parallel-vars: 1.0.1 - clean-yaml-object: 0.1.0 - cli-truncate: 3.1.0 - code-excerpt: 4.0.0 - common-path-prefix: 3.0.0 - concordance: 5.0.4 - currently-unhandled: 0.4.1 - debug: 4.3.4 - del: 6.1.1 - emittery: 0.11.0 - figures: 4.0.1 - globby: 13.1.2 - ignore-by-default: 2.1.0 - indent-string: 5.0.0 - is-error: 2.2.2 - is-plain-object: 5.0.0 - is-promise: 4.0.0 - matcher: 5.0.0 - mem: 9.0.2 - ms: 2.1.3 - p-event: 5.0.1 - p-map: 5.5.0 - picomatch: 2.3.1 - pkg-conf: 4.0.0 - plur: 5.1.0 - pretty-ms: 7.0.1 - resolve-cwd: 3.0.0 - slash: 3.0.0 - stack-utils: 2.0.5 - strip-ansi: 7.0.1 - supertap: 3.0.1 - temp-dir: 2.0.0 - write-file-atomic: 4.0.2 - yargs: 17.6.0 - transitivePeerDependencies: - - supports-color + browserslist: 4.21.5 + caniuse-lite: 1.0.30001482 + fraction.js: 4.2.0 + normalize-range: 0.1.2 + picocolors: 1.0.0 + postcss: 8.4.32 + postcss-value-parser: 4.2.0 dev: true - /ava@5.3.1: - resolution: {integrity: sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg==} - engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} + /ava@6.0.1(@ava/typescript@4.1.0): + resolution: {integrity: sha512-9zR0wOwlcJdOWwHOKnpi0GrPRLTlxDFapGalP4rGD0oQRKxDVoucBBWvxVQ/2cPv10Hx1PkDXLJH5iUzhPn0/g==} + engines: {node: ^18.18 || ^20.8 || ^21} hasBin: true peerDependencies: '@ava/typescript': '*' @@ -6830,53 +7359,57 @@ packages: '@ava/typescript': optional: true dependencies: - acorn: 8.8.2 - acorn-walk: 8.2.0 + '@ava/typescript': 4.1.0 + '@vercel/nft': 0.24.4 + acorn: 8.11.2 + acorn-walk: 8.3.1 ansi-styles: 6.2.1 arrgv: 1.0.2 arrify: 3.0.0 - callsites: 4.0.0 - cbor: 8.1.0 + callsites: 4.1.0 + cbor: 9.0.1 chalk: 5.3.0 - chokidar: 3.5.3 chunkd: 2.0.1 - ci-info: 3.8.0 + ci-info: 4.0.0 ci-parallel-vars: 1.0.1 - clean-yaml-object: 0.1.0 - cli-truncate: 3.1.0 + cli-truncate: 4.0.0 code-excerpt: 4.0.0 common-path-prefix: 3.0.0 concordance: 5.0.4 currently-unhandled: 0.4.1 debug: 4.3.4 emittery: 1.0.1 - figures: 5.0.0 - globby: 13.2.2 + figures: 6.0.1 + globby: 14.0.0 ignore-by-default: 2.1.0 indent-string: 5.0.0 - is-error: 2.2.2 is-plain-object: 5.0.0 is-promise: 4.0.0 matcher: 5.0.0 - mem: 9.0.2 + memoize: 10.0.0 ms: 2.1.3 - p-event: 5.0.1 - p-map: 5.5.0 - picomatch: 2.3.1 - pkg-conf: 4.0.0 + p-map: 6.0.0 + package-config: 5.0.0 + picomatch: 3.0.1 plur: 5.1.0 pretty-ms: 8.0.0 resolve-cwd: 3.0.0 stack-utils: 2.0.6 - strip-ansi: 7.0.1 + strip-ansi: 7.1.0 supertap: 3.0.1 temp-dir: 3.0.0 write-file-atomic: 5.0.1 yargs: 17.7.2 transitivePeerDependencies: + - encoding - supports-color dev: true + /available-typed-arrays@1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + dev: true + /aws-sign2@0.7.0: resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} dev: true @@ -6885,8 +7418,8 @@ packages: resolution: {integrity: sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==} dev: true - /axe-core@4.5.0: - resolution: {integrity: sha512-4+rr8eQ7+XXS5nZrKcMO/AikHL0hVqy+lHWAnE3xdHl+aguag8SOQ6eEqLexwLNWgXIMfunGuD3ON1/6Kyet0A==} + /axe-core@4.7.0: + resolution: {integrity: sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==} engines: {node: '>=4'} dev: true @@ -6898,8 +7431,10 @@ packages: - debug dev: true - /axobject-query@2.2.0: - resolution: {integrity: sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==} + /axobject-query@3.2.1: + resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} + dependencies: + dequal: 2.0.3 dev: true /babel-esm-plugin@0.9.0(webpack@4.46.0): @@ -6912,7 +7447,7 @@ packages: webpack: 4.46.0 dev: true - /babel-loader@8.2.5(@babel/core@7.18.9)(webpack@4.46.0): + /babel-loader@8.2.5(@babel/core@7.18.9)(webpack@4.47.0): resolution: {integrity: sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==} engines: {node: '>= 8.9'} peerDependencies: @@ -6924,7 +7459,7 @@ packages: loader-utils: 2.0.3 make-dir: 3.1.0 schema-utils: 2.7.1 - webpack: 4.46.0 + webpack: 4.47.0 dev: true /babel-loader@8.2.5(@babel/core@7.22.1)(webpack@4.46.0): @@ -6942,12 +7477,12 @@ packages: webpack: 4.46.0 dev: true - /babel-merge@3.0.0(@babel/core@7.22.1): + /babel-merge@3.0.0(@babel/core@7.23.5): resolution: {integrity: sha512-eBOBtHnzt9xvnjpYNI5HmaPp/b2vMveE5XggzqHnQeHJ8mFIBrBv6WZEVIj5jJ2uwTItkqKo9gWzEEcBxEq0yw==} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.22.1 + '@babel/core': 7.23.5 deepmerge: 2.2.1 object.omit: 3.0.0 dev: true @@ -6961,53 +7496,41 @@ packages: resolve: 1.22.2 dev: true - /babel-plugin-polyfill-corejs2@0.3.3(@babel/core@7.18.9): - resolution: {integrity: sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/compat-data': 7.19.4 - '@babel/core': 7.18.9 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.18.9) - semver: 6.3.0 - transitivePeerDependencies: - - supports-color - dev: true - /babel-plugin-polyfill-corejs2@0.3.3(@babel/core@7.22.1): resolution: {integrity: sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.19.4 + '@babel/compat-data': 7.23.5 '@babel/core': 7.22.1 '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.22.1) - semver: 6.3.0 + semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /babel-plugin-polyfill-corejs2@0.4.3(@babel/core@7.22.1): - resolution: {integrity: sha512-bM3gHc337Dta490gg+/AseNB9L4YLHxq1nGKZZSHbhXv4aTYU2MD2cjza1Ru4S6975YLTaL1K8uJf6ukJhhmtw==} + /babel-plugin-polyfill-corejs2@0.4.6(@babel/core@7.18.9): + resolution: {integrity: sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/compat-data': 7.22.3 - '@babel/core': 7.22.1 - '@babel/helper-define-polyfill-provider': 0.4.0(@babel/core@7.22.1) - semver: 6.3.0 + '@babel/compat-data': 7.23.5 + '@babel/core': 7.18.9 + '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.18.9) + semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /babel-plugin-polyfill-corejs3@0.6.0(@babel/core@7.18.9): - resolution: {integrity: sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==} + /babel-plugin-polyfill-corejs2@0.4.6(@babel/core@7.23.5): + resolution: {integrity: sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.18.9) - core-js-compat: 3.26.0 + '@babel/compat-data': 7.23.5 + '@babel/core': 7.23.5 + '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.23.5) + semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true @@ -7019,30 +7542,31 @@ packages: dependencies: '@babel/core': 7.22.1 '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.22.1) - core-js-compat: 3.26.0 + core-js-compat: 3.33.3 transitivePeerDependencies: - supports-color dev: true - /babel-plugin-polyfill-corejs3@0.8.1(@babel/core@7.22.1): - resolution: {integrity: sha512-ikFrZITKg1xH6pLND8zT14UPgjKHiGLqex7rGEZCH2EvhsneJaJPemmpQaIZV5AL03II+lXylw3UmddDK8RU5Q==} + /babel-plugin-polyfill-corejs3@0.8.6(@babel/core@7.18.9): + resolution: {integrity: sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-define-polyfill-provider': 0.4.0(@babel/core@7.22.1) - core-js-compat: 3.30.2 + '@babel/core': 7.18.9 + '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.18.9) + core-js-compat: 3.33.3 transitivePeerDependencies: - supports-color dev: true - /babel-plugin-polyfill-regenerator@0.4.1(@babel/core@7.18.9): - resolution: {integrity: sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==} + /babel-plugin-polyfill-corejs3@0.8.6(@babel/core@7.23.5): + resolution: {integrity: sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.18.9 - '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.18.9) + '@babel/core': 7.23.5 + '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.23.5) + core-js-compat: 3.33.3 transitivePeerDependencies: - supports-color dev: true @@ -7058,13 +7582,24 @@ packages: - supports-color dev: true - /babel-plugin-polyfill-regenerator@0.5.0(@babel/core@7.22.1): - resolution: {integrity: sha512-hDJtKjMLVa7Z+LwnTCxoDLQj6wdc+B8dun7ayF2fYieI6OzfuvcLMB32ihJZ4UhCBwNYGl5bg/x/P9cMdnkc2g==} + /babel-plugin-polyfill-regenerator@0.5.3(@babel/core@7.18.9): + resolution: {integrity: sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.22.1 - '@babel/helper-define-polyfill-provider': 0.4.0(@babel/core@7.22.1) + '@babel/core': 7.18.9 + '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.18.9) + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-polyfill-regenerator@0.5.3(@babel/core@7.23.5): + resolution: {integrity: sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.23.5 + '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.23.5) transitivePeerDependencies: - supports-color dev: true @@ -7076,20 +7611,21 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - /base64-inline-loader@1.1.1(webpack@4.46.0): + /base64-inline-loader@1.1.1(webpack@4.47.0): resolution: {integrity: sha512-v/bHvXQ8sW28t9ZwBsFGgyqZw2bpT49/dtPTtlmixoSM/s9wnOngOKFVQLRH8BfMTy6jTl5m5CdvqpZt8y5d6g==} engines: {node: '>=6.2', npm: '>=3.8'} peerDependencies: webpack: ^4.x dependencies: - file-loader: 1.1.11(webpack@4.46.0) + file-loader: 1.1.11(webpack@4.47.0) loader-utils: 1.4.0 mime-types: 2.1.35 - webpack: 4.46.0 + webpack: 4.47.0 dev: true /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + requiresBuild: true /base@0.11.2: resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} @@ -7114,8 +7650,8 @@ packages: tweetnacl: 0.14.5 dev: true - /better-sqlite3@8.4.0: - resolution: {integrity: sha512-NmsNW1CQvqMszu/CFAJ3pLct6NEFlNfuGM6vw72KHkjOD1UDnL96XNN1BMQc1hiHo8vE2GbOWQYIpZ+YM5wrZw==} + /better-sqlite3@9.2.2: + resolution: {integrity: sha512-qwjWB46il0lsDkeB4rSRI96HyDQr8sxeu1MkBVLMrwusq1KRu4Bpt1TMI+8zIJkDUtZ3umjAkaEjIlokZKWCQw==} requiresBuild: true dependencies: bindings: 1.5.0 @@ -7123,8 +7659,8 @@ packages: dev: false optional: true - /big-integer@1.6.51: - resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} + /big-integer@1.6.52: + resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} dev: false @@ -7152,10 +7688,10 @@ packages: requiresBuild: true dependencies: file-uri-to-path: 1.0.0 - optional: true /bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + requiresBuild: true dependencies: buffer: 5.7.1 inherits: 2.0.4 @@ -7234,7 +7770,6 @@ packages: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 - dev: true /braces@2.3.2: resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} @@ -7331,10 +7866,10 @@ packages: resolution: {integrity: sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} dependencies: - caniuse-lite: 1.0.30001482 - electron-to-chromium: 1.4.284 - node-releases: 2.0.10 - update-browserslist-db: 1.0.10(browserslist@4.21.4) + caniuse-lite: 1.0.30001565 + electron-to-chromium: 1.4.597 + node-releases: 2.0.13 + update-browserslist-db: 1.0.13(browserslist@4.21.4) dev: true /browserslist@4.21.5: @@ -7346,6 +7881,28 @@ packages: node-releases: 2.0.10 update-browserslist-db: 1.0.10(browserslist@4.21.5) + /browserslist@4.22.1: + resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001565 + electron-to-chromium: 1.4.597 + node-releases: 2.0.13 + update-browserslist-db: 1.0.13(browserslist@4.22.1) + dev: true + + /browserslist@4.22.2: + resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001570 + electron-to-chromium: 1.4.613 + node-releases: 2.0.14 + update-browserslist-db: 1.0.13(browserslist@4.22.2) + dev: true + /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true @@ -7364,6 +7921,7 @@ packages: /buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + requiresBuild: true dependencies: base64-js: 1.5.1 ieee754: 1.2.1 @@ -7380,7 +7938,7 @@ packages: /builtins@5.0.1: resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==} dependencies: - semver: 7.3.8 + semver: 7.5.4 dev: true /bulma-checkbox@1.2.1: @@ -7431,22 +7989,23 @@ packages: engines: {node: '>= 0.8'} dev: true - /c8@7.12.0: - resolution: {integrity: sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==} - engines: {node: '>=10.12.0'} + /c8@8.0.1: + resolution: {integrity: sha512-EINpopxZNH1mETuI0DzRA4MZpAUH+IFiRhnmFD3vFr3vdrgxqi3VfE3KL0AIL+zDq8rC9bZqwM/VDmmoe04y7w==} + engines: {node: '>=12'} + hasBin: true dependencies: '@bcoe/v8-coverage': 0.2.3 '@istanbuljs/schema': 0.1.3 find-up: 5.0.0 foreground-child: 2.0.0 - istanbul-lib-coverage: 3.2.0 - istanbul-lib-report: 3.0.0 - istanbul-reports: 3.1.5 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-reports: 3.1.6 rimraf: 3.0.2 test-exclude: 6.0.0 - v8-to-istanbul: 9.0.1 - yargs: 16.2.0 - yargs-parser: 20.2.9 + v8-to-istanbul: 9.2.0 + yargs: 17.7.2 + yargs-parser: 21.1.1 dev: true /cacache@12.0.4: @@ -7480,7 +8039,7 @@ packages: glob: 7.2.3 infer-owner: 1.0.4 lru-cache: 6.0.0 - minipass: 3.3.4 + minipass: 3.3.6 minipass-collect: 1.0.2 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 @@ -7540,6 +8099,14 @@ packages: get-intrinsic: 1.1.3 dev: true + /call-bind@1.0.5: + resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} + dependencies: + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + set-function-length: 1.1.1 + dev: true + /caller-callsite@2.0.0: resolution: {integrity: sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==} engines: {node: '>=4'} @@ -7564,8 +8131,8 @@ packages: engines: {node: '>=6'} dev: true - /callsites@4.0.0: - resolution: {integrity: sha512-y3jRROutgpKdz5vzEhWM34TidDU8vkJppF8dszITeb1PQmSqV3DTxyV8G/lyO/DNvtE1YTedehmw9MPZsCBHxQ==} + /callsites@4.1.0: + resolution: {integrity: sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==} engines: {node: '>=12.20'} dev: true @@ -7600,8 +8167,8 @@ packages: /caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} dependencies: - browserslist: 4.21.5 - caniuse-lite: 1.0.30001482 + browserslist: 4.22.1 + caniuse-lite: 1.0.30001565 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 dev: true @@ -7609,13 +8176,21 @@ packages: /caniuse-lite@1.0.30001482: resolution: {integrity: sha512-F1ZInsg53cegyjroxLNW9DmrEQ1SuGRTO1QlpA0o2/6OpQ0gFeDRoq1yFmnr8Sakn9qwwt9DmbxHB6w167OSuQ==} + /caniuse-lite@1.0.30001565: + resolution: {integrity: sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==} + dev: true + + /caniuse-lite@1.0.30001570: + resolution: {integrity: sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==} + dev: true + /caseless@0.12.0: resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} dev: true - /cbor@8.1.0: - resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} - engines: {node: '>=12.19'} + /cbor@9.0.1: + resolution: {integrity: sha512-/TQOWyamDxvVIv+DY9cOLNuABkoyz8K/F3QE56539pGVYohx0+MEA1f4lChFTX79dBTBS7R1PF6ovH7G+VtBfQ==} + engines: {node: '>=16'} dependencies: nofilter: 3.1.0 dev: true @@ -7675,11 +8250,6 @@ packages: supports-color: 7.2.0 dev: true - /chalk@5.1.2: - resolution: {integrity: sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - dev: true - /chalk@5.3.0: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} @@ -7728,6 +8298,7 @@ packages: /chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + requiresBuild: true /chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} @@ -7751,12 +8322,8 @@ packages: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} dev: true - /ci-info@3.5.0: - resolution: {integrity: sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==} - dev: true - - /ci-info@3.8.0: - resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} + /ci-info@4.0.0: + resolution: {integrity: sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==} engines: {node: '>=8'} dev: true @@ -7788,8 +8355,8 @@ packages: source-map: 0.6.1 dev: true - /clean-css@5.3.2: - resolution: {integrity: sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==} + /clean-css@5.3.3: + resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} engines: {node: '>= 10.0'} dependencies: source-map: 0.6.1 @@ -7800,18 +8367,6 @@ packages: engines: {node: '>=6'} dev: true - /clean-stack@4.2.0: - resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} - engines: {node: '>=12'} - dependencies: - escape-string-regexp: 5.0.0 - dev: true - - /clean-yaml-object@0.1.0: - resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} - engines: {node: '>=0.10.0'} - dev: true - /cli-boxes@2.2.1: resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} engines: {node: '>=6'} @@ -7829,12 +8384,12 @@ packages: engines: {node: '>=6'} dev: true - /cli-truncate@3.1.0: - resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + /cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} dependencies: slice-ansi: 5.0.0 - string-width: 5.1.2 + string-width: 7.0.0 dev: true /client-only@0.0.1: @@ -7920,14 +8475,12 @@ packages: engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 - dev: true /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true /color-string@1.9.1: resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} @@ -7936,6 +8489,11 @@ packages: simple-swizzle: 0.2.2 dev: true + /color-support@1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + dev: true + /color@3.2.1: resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} dependencies: @@ -8058,11 +8616,11 @@ packages: dependencies: date-time: 3.1.0 esutils: 2.0.3 - fast-diff: 1.2.0 + fast-diff: 1.3.0 js-string-escape: 1.0.1 lodash: 4.17.21 md5-hex: 3.0.1 - semver: 7.3.8 + semver: 7.5.4 well-known-symbols: 2.0.0 dev: true @@ -8096,6 +8654,10 @@ packages: engines: {node: '>=4'} dev: true + /console-control-strings@1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + dev: true + /constants-browserify@1.0.0: resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} dev: true @@ -8115,6 +8677,10 @@ packages: /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true + /convert-to-spaces@2.0.1: resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -8170,18 +8736,13 @@ packages: /core-js-compat@3.26.0: resolution: {integrity: sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==} dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 dev: true - /core-js-compat@3.30.2: - resolution: {integrity: sha512-nriW1nuJjUgvkEjIot1Spwakz52V9YkYHZAQG6A1eCgC8AA1p0zngrQEP9R0+V6hji5XilWKG1Bd0YRppmGimA==} + /core-js-compat@3.33.3: + resolution: {integrity: sha512-cNzGqFsh3Ot+529GIXacjTJ7kegdt5fPXxCBVS1G0iaZpuo/tBz399ymceLJveQhFFZ8qThHiP3fzuoQjKN2ow==} dependencies: - browserslist: 4.21.5 - dev: true - - /core-js-pure@3.26.0: - resolution: {integrity: sha512-LiN6fylpVBVwT8twhhluD9TzXmZQQsr2I2eIKtWNbZI1XMfBT7CV18itaN6RA7EtQd/SDdRx/wzvAShX2HvhQA==} - requiresBuild: true + browserslist: 4.22.1 dev: true /core-js@3.26.0: @@ -8305,7 +8866,6 @@ packages: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: true /crypto-browserify@3.12.0: resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==} @@ -8364,7 +8924,7 @@ packages: postcss-modules-values: 4.0.0(postcss@8.4.23) postcss-value-parser: 4.2.0 schema-utils: 3.1.1 - semver: 7.3.8 + semver: 7.5.4 webpack: 4.46.0 dev: true @@ -8417,6 +8977,10 @@ packages: engines: {node: '>= 6'} dev: true + /css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + dev: true + /css@2.2.4: resolution: {integrity: sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==} dependencies: @@ -8754,6 +9318,15 @@ packages: resolution: {integrity: sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==} dev: true + /define-data-property@1.1.1: + resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + /define-lazy-prop@2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} @@ -8767,6 +9340,15 @@ packages: object-keys: 1.1.1 dev: true + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + has-property-descriptors: 1.0.1 + object-keys: 1.1.1 + dev: true + /define-property@0.2.5: resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} engines: {node: '>=0.10.0'} @@ -8789,25 +9371,15 @@ packages: isobject: 3.0.1 dev: true - /del@6.1.1: - resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} - engines: {node: '>=10'} - dependencies: - globby: 11.1.0 - graceful-fs: 4.2.10 - is-glob: 4.0.3 - is-path-cwd: 2.2.0 - is-path-inside: 3.0.3 - p-map: 4.0.0 - rimraf: 3.0.2 - slash: 3.0.0 - dev: true - /delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} dev: true + /delegates@1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + dev: true + /depd@1.1.2: resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} engines: {node: '>= 0.6'} @@ -8823,6 +9395,11 @@ packages: engines: {node: '>= 0.6.0'} dev: true + /dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + dev: true + /des.js@1.1.0: resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} dependencies: @@ -8839,8 +9416,6 @@ packages: resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} engines: {node: '>=8'} requiresBuild: true - dev: false - optional: true /detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} @@ -9007,7 +9582,7 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - dev: true + dev: false /ecc-jsbn@0.1.2: resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} @@ -9037,6 +9612,14 @@ packages: /electron-to-chromium@1.4.284: resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==} + /electron-to-chromium@1.4.597: + resolution: {integrity: sha512-0XOQNqHhg2YgRVRUrS4M4vWjFCFIP2ETXcXe/0KIQBjXE9Cpy+tgzzYfuq6HGai3hWq0YywtG+5XK8fyG08EjA==} + dev: true + + /electron-to-chromium@1.4.613: + resolution: {integrity: sha512-r4x5+FowKG6q+/Wj0W9nidx7QO31BJwmR2uEo+Qh3YLGQ8SbBAFuDFpTxzly/I2gsbrFwBuIjrMp423L3O5U3w==} + dev: true + /elliptic@6.5.4: resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} dependencies: @@ -9049,23 +9632,20 @@ packages: minimalistic-crypto-utils: 1.0.1 dev: true - /emittery@0.11.0: - resolution: {integrity: sha512-S/7tzL6v5i+4iJd627Nhv9cLFIo5weAIlGccqJFpnBoDB8U1TF2k5tez4J/QNuxyyhWuFqHg1L84Kd3m7iXg6g==} - engines: {node: '>=12'} - dev: true - /emittery@1.0.1: resolution: {integrity: sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ==} engines: {node: '>=14.16'} dev: true + /emoji-regex@10.3.0: + resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} + dev: true + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: true /emojis-list@2.1.0: resolution: {integrity: sha512-knHEZMgs8BB+MInokmNTg/OyPlAddghe1YBgNwJBc5zsJi/uyIcXoSDsL/W9ymOsBoBGdPIHXYJ9+qKFwRwDng==} @@ -9090,6 +9670,7 @@ packages: /end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + requiresBuild: true dependencies: once: 1.4.0 @@ -9121,6 +9702,11 @@ packages: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} dev: true + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + dev: true + /envinfo@7.8.1: resolution: {integrity: sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==} engines: {node: '>=4'} @@ -9169,16 +9755,95 @@ packages: unbox-primitive: 1.0.2 dev: true + /es-abstract@1.22.3: + resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.2 + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + es-set-tostringtag: 2.0.2 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.2 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + internal-slot: 1.0.6 + is-array-buffer: 3.0.2 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-typed-array: 1.1.12 + is-weakref: 1.0.2 + object-inspect: 1.13.1 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.1 + safe-array-concat: 1.0.1 + safe-regex-test: 1.0.0 + string.prototype.trim: 1.2.8 + string.prototype.trimend: 1.0.7 + string.prototype.trimstart: 1.0.7 + typed-array-buffer: 1.0.0 + typed-array-byte-length: 1.0.0 + typed-array-byte-offset: 1.0.0 + typed-array-length: 1.0.4 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.13 + dev: true + /es-array-method-boxes-properly@1.0.0: resolution: {integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==} dev: true + /es-iterator-helpers@1.0.15: + resolution: {integrity: sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==} + dependencies: + asynciterator.prototype: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-set-tostringtag: 2.0.2 + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + globalthis: 1.0.3 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.6 + iterator.prototype: 1.1.2 + safe-array-concat: 1.0.1 + dev: true + + /es-set-tostringtag@2.0.2: + resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + has-tostringtag: 1.0.0 + hasown: 2.0.0 + dev: true + /es-shim-unscopables@1.0.0: resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} dependencies: has: 1.0.3 dev: true + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + dependencies: + hasown: 2.0.0 + dev: true + /es-to-primitive@1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} @@ -9194,66 +9859,38 @@ packages: /esbuild@0.12.29: resolution: {integrity: sha512-w/XuoBCSwepyiZtIRsKsetiLDUVGPVw1E/R3VTFSecIy8UR7Cq3SOtwKHJMFoVqqVG36aGkzh4e8BvpO1Fdc7g==} + hasBin: true requiresBuild: true dev: true - /esbuild@0.17.19: - resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==} + /esbuild@0.19.9: + resolution: {integrity: sha512-U9CHtKSy+EpPsEBa+/A2gMs/h3ylBC0H0KSqIg7tpztHerLi6nrrcoUJAkNCEPumx8yJ+Byic4BVwHgRbN0TBg==} engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/android-arm': 0.17.19 - '@esbuild/android-arm64': 0.17.19 - '@esbuild/android-x64': 0.17.19 - '@esbuild/darwin-arm64': 0.17.19 - '@esbuild/darwin-x64': 0.17.19 - '@esbuild/freebsd-arm64': 0.17.19 - '@esbuild/freebsd-x64': 0.17.19 - '@esbuild/linux-arm': 0.17.19 - '@esbuild/linux-arm64': 0.17.19 - '@esbuild/linux-ia32': 0.17.19 - '@esbuild/linux-loong64': 0.17.19 - '@esbuild/linux-mips64el': 0.17.19 - '@esbuild/linux-ppc64': 0.17.19 - '@esbuild/linux-riscv64': 0.17.19 - '@esbuild/linux-s390x': 0.17.19 - '@esbuild/linux-x64': 0.17.19 - '@esbuild/netbsd-x64': 0.17.19 - '@esbuild/openbsd-x64': 0.17.19 - '@esbuild/sunos-x64': 0.17.19 - '@esbuild/win32-arm64': 0.17.19 - '@esbuild/win32-ia32': 0.17.19 - '@esbuild/win32-x64': 0.17.19 - dev: true - - /esbuild@0.17.7: - resolution: {integrity: sha512-+5hHlrK108fT6C6/40juy0w4DYKtyZ5NjfBlTccBdsFutR7WBxpIY633JzZJewdsCy8xWA/u2z0MSniIJwufYg==} - engines: {node: '>=12'} - requiresBuild: true - optionalDependencies: - '@esbuild/android-arm': 0.17.7 - '@esbuild/android-arm64': 0.17.7 - '@esbuild/android-x64': 0.17.7 - '@esbuild/darwin-arm64': 0.17.7 - '@esbuild/darwin-x64': 0.17.7 - '@esbuild/freebsd-arm64': 0.17.7 - '@esbuild/freebsd-x64': 0.17.7 - '@esbuild/linux-arm': 0.17.7 - '@esbuild/linux-arm64': 0.17.7 - '@esbuild/linux-ia32': 0.17.7 - '@esbuild/linux-loong64': 0.17.7 - '@esbuild/linux-mips64el': 0.17.7 - '@esbuild/linux-ppc64': 0.17.7 - '@esbuild/linux-riscv64': 0.17.7 - '@esbuild/linux-s390x': 0.17.7 - '@esbuild/linux-x64': 0.17.7 - '@esbuild/netbsd-x64': 0.17.7 - '@esbuild/openbsd-x64': 0.17.7 - '@esbuild/sunos-x64': 0.17.7 - '@esbuild/win32-arm64': 0.17.7 - '@esbuild/win32-ia32': 0.17.7 - '@esbuild/win32-x64': 0.17.7 + '@esbuild/android-arm': 0.19.9 + '@esbuild/android-arm64': 0.19.9 + '@esbuild/android-x64': 0.19.9 + '@esbuild/darwin-arm64': 0.19.9 + '@esbuild/darwin-x64': 0.19.9 + '@esbuild/freebsd-arm64': 0.19.9 + '@esbuild/freebsd-x64': 0.19.9 + '@esbuild/linux-arm': 0.19.9 + '@esbuild/linux-arm64': 0.19.9 + '@esbuild/linux-ia32': 0.19.9 + '@esbuild/linux-loong64': 0.19.9 + '@esbuild/linux-mips64el': 0.19.9 + '@esbuild/linux-ppc64': 0.19.9 + '@esbuild/linux-riscv64': 0.19.9 + '@esbuild/linux-s390x': 0.19.9 + '@esbuild/linux-x64': 0.19.9 + '@esbuild/netbsd-x64': 0.19.9 + '@esbuild/openbsd-x64': 0.19.9 + '@esbuild/sunos-x64': 0.19.9 + '@esbuild/win32-arm64': 0.19.9 + '@esbuild/win32-ia32': 0.19.9 + '@esbuild/win32-x64': 0.19.9 dev: true /escalade@3.1.1: @@ -9300,7 +9937,7 @@ packages: source-map: 0.6.1 dev: true - /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.26.0)(eslint@8.26.0): + /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.1)(eslint@8.26.0): resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -9309,28 +9946,28 @@ packages: dependencies: confusing-browser-globals: 1.0.11 eslint: 8.26.0 - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.41.0)(eslint@8.26.0) - object.assign: 4.1.4 - object.entries: 1.1.5 - semver: 6.3.0 + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.41.0)(eslint@8.26.0) + object.assign: 4.1.5 + object.entries: 1.1.7 + semver: 6.3.1 dev: true - /eslint-config-airbnb-typescript@16.2.0(@typescript-eslint/eslint-plugin@5.41.0)(@typescript-eslint/parser@5.41.0)(eslint-plugin-import@2.26.0)(eslint@8.26.0): - resolution: {integrity: sha512-OUaMPZpTOZGKd5tXOjJ9PRU4iYNW/Z5DoHIynjsVK/FpkWdiY5+nxQW6TiJAlLwVI1l53xUOrnlZWtVBVQzuWA==} + /eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@5.41.0)(@typescript-eslint/parser@5.41.0)(eslint-plugin-import@2.29.1)(eslint@8.26.0): + resolution: {integrity: sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==} peerDependencies: - '@typescript-eslint/eslint-plugin': ^5.0.0 - '@typescript-eslint/parser': ^5.0.0 + '@typescript-eslint/eslint-plugin': ^5.13.0 || ^6.0.0 + '@typescript-eslint/parser': ^5.0.0 || ^6.0.0 eslint: ^7.32.0 || ^8.2.0 eslint-plugin-import: ^2.25.3 dependencies: - '@typescript-eslint/eslint-plugin': 5.41.0(@typescript-eslint/parser@5.41.0)(eslint@8.26.0)(typescript@5.2.2) - '@typescript-eslint/parser': 5.41.0(eslint@8.26.0)(typescript@5.2.2) + '@typescript-eslint/eslint-plugin': 5.41.0(@typescript-eslint/parser@5.41.0)(eslint@8.26.0)(typescript@5.3.3) + '@typescript-eslint/parser': 5.41.0(eslint@8.26.0)(typescript@5.3.3) eslint: 8.26.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.26.0)(eslint@8.26.0) - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.41.0)(eslint@8.26.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1)(eslint@8.26.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.41.0)(eslint@8.26.0) dev: true - /eslint-config-preact@1.3.0(@typescript-eslint/eslint-plugin@4.33.0)(eslint@7.32.0)(typescript@5.2.2): + /eslint-config-preact@1.3.0(@typescript-eslint/eslint-plugin@4.33.0)(eslint@7.32.0)(typescript@5.3.3): resolution: {integrity: sha512-yHYXg5qNzEJd3D/30AmsIW0W8MuY858KpApXp7xxBF08IYUljSKCOqMx+dVucXHQnAm7+11wOnMkgVHIBAechw==} peerDependencies: eslint: 6.x || 7.x || 8.x @@ -9342,7 +9979,7 @@ packages: '@babel/plugin-syntax-jsx': 7.21.4(@babel/core@7.18.9) eslint: 7.32.0 eslint-plugin-compat: 4.0.2(eslint@7.32.0) - eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@4.33.0)(eslint@7.32.0)(typescript@5.2.2) + eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@4.33.0)(eslint@7.32.0)(typescript@5.3.3) eslint-plugin-react: 7.31.10(eslint@7.32.0) eslint-plugin-react-hooks: 4.6.0(eslint@7.32.0) transitivePeerDependencies: @@ -9352,21 +9989,21 @@ packages: - typescript dev: true - /eslint-config-preact@1.3.0(@typescript-eslint/eslint-plugin@5.41.0)(eslint@8.48.0)(typescript@5.2.2): + /eslint-config-preact@1.3.0(@typescript-eslint/eslint-plugin@5.41.0)(eslint@8.55.0)(typescript@5.3.3): resolution: {integrity: sha512-yHYXg5qNzEJd3D/30AmsIW0W8MuY858KpApXp7xxBF08IYUljSKCOqMx+dVucXHQnAm7+11wOnMkgVHIBAechw==} peerDependencies: eslint: 6.x || 7.x || 8.x dependencies: '@babel/core': 7.18.9 - '@babel/eslint-parser': 7.19.1(@babel/core@7.18.9)(eslint@8.48.0) + '@babel/eslint-parser': 7.19.1(@babel/core@7.18.9)(eslint@8.55.0) '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.18.9) '@babel/plugin-syntax-decorators': 7.19.0(@babel/core@7.18.9) '@babel/plugin-syntax-jsx': 7.21.4(@babel/core@7.18.9) - eslint: 8.48.0 - eslint-plugin-compat: 4.0.2(eslint@8.48.0) - eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.41.0)(eslint@8.48.0)(typescript@5.2.2) - eslint-plugin-react: 7.31.10(eslint@8.48.0) - eslint-plugin-react-hooks: 4.6.0(eslint@8.48.0) + eslint: 8.55.0 + eslint-plugin-compat: 4.0.2(eslint@8.55.0) + eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.41.0)(eslint@8.55.0)(typescript@5.3.3) + eslint-plugin-react: 7.31.10(eslint@8.55.0) + eslint-plugin-react-hooks: 4.6.0(eslint@8.55.0) transitivePeerDependencies: - '@typescript-eslint/eslint-plugin' - jest @@ -9374,17 +10011,18 @@ packages: - typescript dev: true - /eslint-import-resolver-node@0.3.6: - resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==} + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: debug: 3.2.7 - resolve: 1.22.2 + is-core-module: 2.13.1 + resolve: 1.22.8 transitivePeerDependencies: - supports-color dev: true - /eslint-module-utils@2.7.4(@typescript-eslint/parser@5.41.0)(eslint-import-resolver-node@0.3.6)(eslint@8.26.0): - resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} + /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.41.0)(eslint-import-resolver-node@0.3.9)(eslint@8.26.0): + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -9404,10 +10042,10 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.41.0(eslint@8.26.0)(typescript@5.2.2) + '@typescript-eslint/parser': 5.41.0(eslint@8.26.0)(typescript@5.3.3) debug: 3.2.7 eslint: 8.26.0 - eslint-import-resolver-node: 0.3.6 + eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color dev: true @@ -9429,7 +10067,7 @@ packages: semver: 7.3.5 dev: true - /eslint-plugin-compat@4.0.2(eslint@8.48.0): + /eslint-plugin-compat@4.0.2(eslint@8.55.0): resolution: {integrity: sha512-xqvoO54CLTVaEYGMzhu35Wzwk/As7rCvz/2dqwnFiWi0OJccEtGIn+5qq3zqIu9nboXlpdBN579fZcItC73Ycg==} engines: {node: '>=9.x'} peerDependencies: @@ -9440,7 +10078,7 @@ packages: browserslist: 4.21.5 caniuse-lite: 1.0.30001482 core-js: 3.26.0 - eslint: 8.48.0 + eslint: 8.55.0 find-up: 5.0.0 lodash.memoize: 4.1.2 semver: 7.3.5 @@ -9454,8 +10092,8 @@ packages: eslint: 7.32.0 dev: true - /eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.41.0)(eslint@8.26.0): - resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.41.0)(eslint@8.26.0): + resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -9464,28 +10102,32 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.41.0(eslint@8.26.0)(typescript@5.2.2) - array-includes: 3.1.5 - array.prototype.flat: 1.3.0 - debug: 2.6.9 + '@typescript-eslint/parser': 5.41.0(eslint@8.26.0)(typescript@5.3.3) + array-includes: 3.1.7 + array.prototype.findlastindex: 1.2.3 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 doctrine: 2.1.0 eslint: 8.26.0 - eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.41.0)(eslint-import-resolver-node@0.3.6)(eslint@8.26.0) - has: 1.0.3 - is-core-module: 2.11.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.41.0)(eslint-import-resolver-node@0.3.9)(eslint@8.26.0) + hasown: 2.0.0 + is-core-module: 2.13.1 is-glob: 4.0.3 minimatch: 3.1.2 - object.values: 1.1.5 - resolve: 1.22.1 - tsconfig-paths: 3.14.1 + object.fromentries: 2.0.7 + object.groupby: 1.0.1 + object.values: 1.1.7 + semver: 6.3.1 + tsconfig-paths: 3.15.0 transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color dev: true - /eslint-plugin-jest@25.7.0(@typescript-eslint/eslint-plugin@4.33.0)(eslint@7.32.0)(typescript@5.2.2): + /eslint-plugin-jest@25.7.0(@typescript-eslint/eslint-plugin@4.33.0)(eslint@7.32.0)(typescript@5.3.3): resolution: {integrity: sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} peerDependencies: @@ -9498,15 +10140,15 @@ packages: jest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.2.2) - '@typescript-eslint/experimental-utils': 5.41.0(eslint@7.32.0)(typescript@5.2.2) + '@typescript-eslint/eslint-plugin': 4.33.0(@typescript-eslint/parser@4.33.0)(eslint@7.32.0)(typescript@5.3.3) + '@typescript-eslint/experimental-utils': 5.41.0(eslint@7.32.0)(typescript@5.3.3) eslint: 7.32.0 transitivePeerDependencies: - supports-color - typescript dev: true - /eslint-plugin-jest@25.7.0(@typescript-eslint/eslint-plugin@5.41.0)(eslint@8.48.0)(typescript@5.2.2): + /eslint-plugin-jest@25.7.0(@typescript-eslint/eslint-plugin@5.41.0)(eslint@8.55.0)(typescript@5.3.3): resolution: {integrity: sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} peerDependencies: @@ -9519,34 +10161,37 @@ packages: jest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 5.41.0(@typescript-eslint/parser@5.41.0)(eslint@8.48.0)(typescript@5.2.2) - '@typescript-eslint/experimental-utils': 5.41.0(eslint@8.48.0)(typescript@5.2.2) - eslint: 8.48.0 + '@typescript-eslint/eslint-plugin': 5.41.0(@typescript-eslint/parser@5.41.0)(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/experimental-utils': 5.41.0(eslint@8.55.0)(typescript@5.3.3) + eslint: 8.55.0 transitivePeerDependencies: - supports-color - typescript dev: true - /eslint-plugin-jsx-a11y@6.6.1(eslint@8.26.0): - resolution: {integrity: sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==} + /eslint-plugin-jsx-a11y@6.8.0(eslint@8.26.0): + resolution: {integrity: sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==} engines: {node: '>=4.0'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: - '@babel/runtime': 7.19.4 - aria-query: 4.2.2 - array-includes: 3.1.5 - ast-types-flow: 0.0.7 - axe-core: 4.5.0 - axobject-query: 2.2.0 + '@babel/runtime': 7.23.6 + aria-query: 5.3.0 + array-includes: 3.1.7 + array.prototype.flatmap: 1.3.2 + ast-types-flow: 0.0.8 + axe-core: 4.7.0 + axobject-query: 3.2.1 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 + es-iterator-helpers: 1.0.15 eslint: 8.26.0 - has: 1.0.3 - jsx-ast-utils: 3.3.3 - language-tags: 1.0.5 + hasown: 2.0.0 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 minimatch: 3.1.2 - semver: 6.3.0 + object.entries: 1.1.7 + object.fromentries: 2.0.7 dev: true /eslint-plugin-react-hooks@4.6.0(eslint@7.32.0): @@ -9567,13 +10212,13 @@ packages: eslint: 8.26.0 dev: true - /eslint-plugin-react-hooks@4.6.0(eslint@8.48.0): + /eslint-plugin-react-hooks@4.6.0(eslint@8.55.0): resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} engines: {node: '>=10'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 dependencies: - eslint: 8.48.0 + eslint: 8.55.0 dev: true /eslint-plugin-react@7.31.10(eslint@7.32.0): @@ -9599,7 +10244,7 @@ packages: string.prototype.matchall: 4.0.7 dev: true - /eslint-plugin-react@7.31.10(eslint@8.26.0): + /eslint-plugin-react@7.31.10(eslint@8.55.0): resolution: {integrity: sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==} engines: {node: '>=4'} peerDependencies: @@ -9608,7 +10253,7 @@ packages: array-includes: 3.1.5 array.prototype.flatmap: 1.3.0 doctrine: 2.1.0 - eslint: 8.26.0 + eslint: 8.55.0 estraverse: 5.3.0 jsx-ast-utils: 3.3.3 minimatch: 3.1.2 @@ -9622,27 +10267,29 @@ packages: string.prototype.matchall: 4.0.7 dev: true - /eslint-plugin-react@7.31.10(eslint@8.48.0): - resolution: {integrity: sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==} + /eslint-plugin-react@7.33.2(eslint@8.26.0): + resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} engines: {node: '>=4'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: - array-includes: 3.1.5 - array.prototype.flatmap: 1.3.0 + array-includes: 3.1.7 + array.prototype.flatmap: 1.3.2 + array.prototype.tosorted: 1.1.2 doctrine: 2.1.0 - eslint: 8.48.0 + es-iterator-helpers: 1.0.15 + eslint: 8.26.0 estraverse: 5.3.0 - jsx-ast-utils: 3.3.3 + jsx-ast-utils: 3.3.5 minimatch: 3.1.2 - object.entries: 1.1.5 - object.fromentries: 2.0.5 - object.hasown: 1.1.1 - object.values: 1.1.5 + object.entries: 1.1.7 + object.fromentries: 2.0.7 + object.hasown: 1.1.3 + object.values: 1.1.7 prop-types: 15.8.1 - resolve: 2.0.0-next.4 - semver: 6.3.0 - string.prototype.matchall: 4.0.7 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.10 dev: true /eslint-scope@4.0.3: @@ -9704,13 +10351,13 @@ packages: eslint-visitor-keys: 2.1.0 dev: true - /eslint-utils@3.0.0(eslint@8.48.0): + /eslint-utils@3.0.0(eslint@8.55.0): resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: eslint: '>=5' dependencies: - eslint: 8.48.0 + eslint: 8.55.0 eslint-visitor-keys: 2.1.0 dev: true @@ -9829,18 +10476,19 @@ packages: - supports-color dev: true - /eslint@8.48.0: - resolution: {integrity: sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==} + /eslint@8.55.0: + resolution: {integrity: sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0) - '@eslint-community/regexpp': 4.8.0 - '@eslint/eslintrc': 2.1.2 - '@eslint/js': 8.48.0 - '@humanwhocodes/config-array': 0.11.11 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) + '@eslint-community/regexpp': 4.10.0 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.55.0 + '@humanwhocodes/config-array': 0.11.13 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 @@ -9856,9 +10504,9 @@ packages: file-entry-cache: 6.0.1 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.21.0 + globals: 13.24.0 graphemer: 1.4.0 - ignore: 5.2.4 + ignore: 5.3.0 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 @@ -9902,14 +10550,15 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.10.0 - acorn-jsx: 5.3.2(acorn@8.10.0) + acorn: 8.11.2 + acorn-jsx: 5.3.2(acorn@8.11.2) eslint-visitor-keys: 3.4.3 dev: true /esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} + hasBin: true dev: true /esquery@1.4.0: @@ -9947,6 +10596,10 @@ packages: resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} dev: true + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: true + /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -9988,8 +10641,8 @@ packages: strip-final-newline: 2.0.0 dev: true - /execa@7.1.1: - resolution: {integrity: sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==} + /execa@7.2.0: + resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==} engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} dependencies: cross-spawn: 7.0.3 @@ -10108,12 +10761,12 @@ packages: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true - /fast-diff@1.2.0: - resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} + /fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} dev: true - /fast-glob@3.2.12: - resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} + /fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} engines: {node: '>=8.6.0'} dependencies: '@nodelib/fs.stat': 2.0.5 @@ -10121,10 +10774,9 @@ packages: glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.5 - dev: true - /fast-glob@3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} dependencies: '@nodelib/fs.stat': 2.0.5 @@ -10132,6 +10784,7 @@ packages: glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.5 + dev: true /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -10153,28 +10806,19 @@ packages: websocket-driver: 0.7.4 dev: true - /fflate@0.7.4: - resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==} + /fflate@0.8.1: + resolution: {integrity: sha512-/exOvEuc+/iaUm105QIiOt4LpBdMTWsXxqR0HDF35vx3fmaKzw7354gTilCh5rkzEt8WYyG//ku3h3nRmd7CHQ==} dev: false /figgy-pudding@3.5.2: resolution: {integrity: sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==} dev: true - /figures@4.0.1: - resolution: {integrity: sha512-rElJwkA/xS04Vfg+CaZodpso7VqBknOYbzi6I76hI4X80RUjkSxO2oAyPmGbuXUppywjqndOrQDl817hDnI++w==} - engines: {node: '>=12'} - dependencies: - escape-string-regexp: 5.0.0 - is-unicode-supported: 1.3.0 - dev: true - - /figures@5.0.0: - resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==} - engines: {node: '>=14'} + /figures@6.0.1: + resolution: {integrity: sha512-0oY/olScYD4IhQ8u//gCPA4F3mlTn2dacYmiDm/mbDQvpmLjV4uH+zhsQ5IyXRyvqkvtUkXkNdGvg5OFJTCsuQ==} + engines: {node: '>=18'} dependencies: - escape-string-regexp: 5.0.0 - is-unicode-supported: 1.3.0 + is-unicode-supported: 2.0.0 dev: true /file-entry-cache@6.0.1: @@ -10184,7 +10828,7 @@ packages: flat-cache: 3.0.4 dev: true - /file-loader@1.1.11(webpack@4.46.0): + /file-loader@1.1.11(webpack@4.47.0): resolution: {integrity: sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==} engines: {node: '>= 4.3 < 5.0.0 || >= 5.10'} peerDependencies: @@ -10192,7 +10836,7 @@ packages: dependencies: loader-utils: 1.4.0 schema-utils: 0.4.7 - webpack: 4.46.0 + webpack: 4.47.0 dev: true /file-loader@6.2.0(webpack@4.46.0): @@ -10209,7 +10853,6 @@ packages: /file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} requiresBuild: true - optional: true /filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} @@ -10266,6 +10909,11 @@ packages: pkg-dir: 4.2.0 dev: true + /find-up-simple@1.0.0: + resolution: {integrity: sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==} + engines: {node: '>=18'} + dev: true + /find-up@3.0.0: resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} engines: {node: '>=6'} @@ -10289,14 +10937,6 @@ packages: path-exists: 4.0.0 dev: true - /find-up@6.3.0: - resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - locate-path: 7.1.1 - path-exists: 5.0.0 - dev: true - /flat-cache@3.0.4: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -10349,6 +10989,14 @@ packages: signal-exit: 3.0.7 dev: true + /foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + dev: false + /forever-agent@0.6.1: resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} dev: true @@ -10367,7 +11015,7 @@ packages: vue-template-compiler: optional: true dependencies: - '@babel/code-frame': 7.21.4 + '@babel/code-frame': 7.23.5 chalk: 2.4.2 micromatch: 3.1.10 minimatch: 3.1.2 @@ -10456,7 +11104,7 @@ packages: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} dependencies: - minipass: 3.3.4 + minipass: 3.3.6 dev: true /fs-monkey@1.0.3: @@ -10483,7 +11131,7 @@ packages: requiresBuild: true dependencies: bindings: 1.5.0 - nan: 2.17.0 + nan: 2.18.0 dev: true optional: true @@ -10497,6 +11145,10 @@ packages: /function-bind@1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + /function.prototype.name@1.1.5: resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} engines: {node: '>= 0.4'} @@ -10507,6 +11159,16 @@ packages: functions-have-names: 1.2.3 dev: true + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + functions-have-names: 1.2.3 + dev: true + /functional-red-black-tree@1.0.1: resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} dev: true @@ -10515,6 +11177,21 @@ packages: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true + /gauge@3.0.2: + resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} + engines: {node: '>=10'} + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + object-assign: 4.1.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + dev: true + /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -10524,6 +11201,11 @@ packages: engines: {node: 6.* || 8.* || >= 10.*} dev: true + /get-east-asian-width@1.2.0: + resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==} + engines: {node: '>=18'} + dev: true + /get-func-name@2.0.0: resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} dev: true @@ -10536,6 +11218,15 @@ packages: has-symbols: 1.0.3 dev: true + /get-intrinsic@1.2.2: + resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} + dependencies: + function-bind: 1.1.2 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + dev: true + /get-own-enumerable-property-symbols@3.0.2: resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} dev: true @@ -10639,6 +11330,18 @@ packages: dependencies: is-glob: 4.0.3 + /glob@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.3 + minipass: 7.0.4 + path-scurry: 1.10.1 + dev: false + /glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} dependencies: @@ -10669,9 +11372,10 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 + dev: true - /glob@8.0.3: - resolution: {integrity: sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==} + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} dependencies: fs.realpath: 1.0.0 @@ -10706,6 +11410,20 @@ packages: type-fest: 0.20.2 dev: true + /globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.1 + dev: true + /globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} @@ -10718,17 +11436,6 @@ packages: slash: 3.0.0 dev: true - /globby@13.1.2: - resolution: {integrity: sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - dir-glob: 3.0.1 - fast-glob: 3.2.12 - ignore: 5.2.0 - merge2: 1.4.1 - slash: 4.0.0 - dev: true - /globby@13.2.2: resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -10740,6 +11447,24 @@ packages: slash: 4.0.0 dev: true + /globby@14.0.0: + resolution: {integrity: sha512-/1WM/LNHRAOH9lZta77uGbq0dAEQM+XjNesWwhlERDVenqothRbnzTrL3/LrIoEPPjeUHC3vrS6TwoyxeHs7MQ==} + engines: {node: '>=18'} + dependencies: + '@sindresorhus/merge-streams': 1.0.0 + fast-glob: 3.3.2 + ignore: 5.3.0 + path-type: 5.0.0 + slash: 5.1.0 + unicorn-magic: 0.1.0 + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + /got@9.6.0: resolution: {integrity: sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==} engines: {node: '>=8.6'} @@ -10759,10 +11484,6 @@ packages: url-parse-lax: 3.0.0 dev: true - /graceful-fs@4.2.10: - resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - dev: true - /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} dev: true @@ -10791,6 +11512,17 @@ packages: resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} dev: true + /happy-dom@10.8.0: + resolution: {integrity: sha512-ux5UfhNA9ANGf4keV7FCd9GqeQr3Bz1u9qnoPtTL0NcO1MEOeUXIUwNTB9r84Z7Q8/bsgkwi6K114zjYvnCmag==} + dependencies: + css.escape: 1.5.1 + entities: 4.5.0 + iconv-lite: 0.6.3 + webidl-conversions: 7.0.0 + whatwg-encoding: 2.0.0 + whatwg-mimetype: 3.0.0 + dev: true + /har-schema@2.0.0: resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} engines: {node: '>=4'} @@ -10828,6 +11560,17 @@ packages: get-intrinsic: 1.1.3 dev: true + /has-property-descriptors@1.0.1: + resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: true + /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} @@ -10840,6 +11583,10 @@ packages: has-symbols: 1.0.3 dev: true + /has-unicode@2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + dev: true + /has-value@0.3.1: resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} engines: {node: '>=0.10.0'} @@ -10891,8 +11638,8 @@ packages: safe-buffer: 5.2.1 dev: true - /hash-wasm@4.9.0: - resolution: {integrity: sha512-7SW7ejyfnRxuOc7ptQHSf4LDoZaWOivfzqw+5rpcQku0nHfmicPKE51ra9BiRLAmT8+gGLestr1XroUkqdjL6w==} + /hash-wasm@4.11.0: + resolution: {integrity: sha512-HVusNXlVqHe0fzIzdQOGolnFN6mX/fqcrSAOcTBXdvzrXVHwTz11vXeKRmkR5gTuwVpvHZEIyKoePDvuAR+XwQ==} dev: false /hash.js@1.1.7: @@ -10910,6 +11657,13 @@ packages: type-fest: 0.8.1 dev: true + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} dev: true @@ -10978,12 +11732,12 @@ packages: hasBin: true dependencies: camel-case: 4.1.2 - clean-css: 5.3.2 + clean-css: 5.3.3 commander: 8.3.0 he: 1.2.0 param-case: 3.0.4 relateurl: 0.2.7 - terser: 5.19.4 + terser: 5.26.0 dev: true /html-minifier@3.5.21: @@ -11035,8 +11789,8 @@ packages: webpack: 4.46.0 dev: true - /html-webpack-plugin@5.5.3(webpack@4.46.0): - resolution: {integrity: sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==} + /html-webpack-plugin@5.5.4(webpack@4.47.0): + resolution: {integrity: sha512-3wNSaVVxdxcu0jd4FpQFoICdqgxs4zIQQvj+2yQKFfBOnLETQ6X5CDWdeasuGlSsooFlMkEioWDTqBv1wvw5Iw==} engines: {node: '>=10.13.0'} peerDependencies: webpack: ^5.20.0 @@ -11046,18 +11800,18 @@ packages: lodash: 4.17.21 pretty-error: 4.0.0 tapable: 2.2.1 - webpack: 4.46.0 + webpack: 4.47.0 dev: true - /html-webpack-skip-assets-plugin@1.0.3(html-webpack-plugin@5.5.3)(webpack@4.46.0): + /html-webpack-skip-assets-plugin@1.0.3(html-webpack-plugin@5.5.4)(webpack@4.47.0): resolution: {integrity: sha512-vpdh+JZGlE1Df3IftH2gw5P7b6yfTsahcOIJnkkkj5iJU9dUStXgzgALoXWwl8+17wWgFm3edcJzeYTJBYfMAw==} peerDependencies: html-webpack-plugin: '>=3.0.0' webpack: '>=3.0.0' dependencies: - html-webpack-plugin: 5.5.3(webpack@4.46.0) + html-webpack-plugin: 5.5.4(webpack@4.47.0) minimatch: 3.0.4 - webpack: 4.46.0 + webpack: 4.47.0 dev: true /htmlparser2@6.1.0: @@ -11145,6 +11899,16 @@ packages: resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} dev: true + /https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -11184,6 +11948,7 @@ packages: /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + requiresBuild: true /iferr@0.1.5: resolution: {integrity: sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==} @@ -11209,6 +11974,11 @@ packages: engines: {node: '>= 4'} dev: true + /ignore@5.3.0: + resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} + engines: {node: '>= 4'} + dev: true + /immutable@4.1.0: resolution: {integrity: sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==} dev: true @@ -11296,6 +12066,15 @@ packages: side-channel: 1.0.4 dev: true + /internal-slot@1.0.6: + resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + hasown: 2.0.0 + side-channel: 1.0.4 + dev: true + /ip@1.1.8: resolution: {integrity: sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==} dev: true @@ -11310,8 +12089,8 @@ packages: engines: {node: '>= 10'} dev: true - /irregular-plurals@3.3.0: - resolution: {integrity: sha512-MVBLKUTangM3EfRPFROhmWQQKRDsrgI83J8GS3jXy+OwYqiR2/aoWndYQ5416jLE3uaGgLH7ncme3X9y09gZ3g==} + /irregular-plurals@3.5.0: + resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} engines: {node: '>=8'} dev: true @@ -11334,6 +12113,14 @@ packages: kind-of: 6.0.3 dev: true + /is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: true + /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true @@ -11342,6 +12129,13 @@ packages: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} dev: true + /is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: @@ -11402,6 +12196,12 @@ packages: dependencies: has: 1.0.3 + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.0 + dev: true + /is-data-descriptor@0.1.4: resolution: {integrity: sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==} engines: {node: '>=0.10.0'} @@ -11451,10 +12251,6 @@ packages: engines: {node: '>=8'} dev: true - /is-error@2.2.2: - resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==} - dev: true - /is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} @@ -11471,16 +12267,28 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + /is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + dependencies: + call-bind: 1.0.5 + dev: true + /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - dev: true /is-fullwidth-code-point@4.0.0: resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} engines: {node: '>=12'} dev: true + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + /is-glob@3.1.0: resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} engines: {node: '>=0.10.0'} @@ -11509,6 +12317,10 @@ packages: engines: {node: '>=8'} dev: true + /is-map@2.0.2: + resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} + dev: true + /is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} dev: true @@ -11551,11 +12363,6 @@ packages: engines: {node: '>=8'} dev: true - /is-path-cwd@2.2.0: - resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} - engines: {node: '>=6'} - dev: true - /is-path-inside@3.0.3: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} @@ -11604,6 +12411,10 @@ packages: resolution: {integrity: sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==} dev: true + /is-set@2.0.2: + resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} + dev: true + /is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: @@ -11634,6 +12445,13 @@ packages: has-symbols: 1.0.3 dev: true + /is-typed-array@1.1.12: + resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.13 + dev: true + /is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} dev: true @@ -11643,15 +12461,26 @@ packages: engines: {node: '>=10'} dev: true - /is-unicode-supported@1.3.0: - resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} - engines: {node: '>=12'} + /is-unicode-supported@2.0.0: + resolution: {integrity: sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==} + engines: {node: '>=18'} + dev: true + + /is-weakmap@2.0.1: + resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} dev: true /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.2 + dev: true + + /is-weakset@2.0.2: + resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 dev: true /is-windows@1.0.2: @@ -11679,9 +12508,12 @@ packages: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} dev: true + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true + /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true /isobject@2.1.0: resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} @@ -11713,6 +12545,11 @@ packages: engines: {node: '>=8'} dev: true + /istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + dev: true + /istanbul-lib-hook@3.0.0: resolution: {integrity: sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==} engines: {node: '>=8'} @@ -11724,10 +12561,10 @@ packages: resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.22.1 + '@babel/core': 7.18.9 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 - semver: 6.3.0 + semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true @@ -11753,6 +12590,15 @@ packages: supports-color: 7.2.0 dev: true + /istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + dev: true + /istanbul-lib-source-maps@4.0.1: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} @@ -11772,6 +12618,33 @@ packages: istanbul-lib-report: 3.0.0 dev: true + /istanbul-reports@3.1.6: + resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + dev: true + + /iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.4 + set-function-name: 2.0.1 + dev: true + + /jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: false + /jake@10.8.5: resolution: {integrity: sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==} engines: {node: '>=10'} @@ -11812,6 +12685,7 @@ packages: /js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true dependencies: argparse: 1.0.10 esprima: 4.0.1 @@ -11863,11 +12737,13 @@ packages: /jsesc@0.5.0: resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} + hasBin: true dev: true /jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} + hasBin: true /json-buffer@3.0.0: resolution: {integrity: sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==} @@ -11906,17 +12782,11 @@ packages: hasBin: true dev: true - /json5@1.0.1: - resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==} - dependencies: - minimist: 1.2.7 - dev: true - /json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true dependencies: - minimist: 1.2.8 + minimist: 1.2.7 dev: true /json5@2.2.1: @@ -11927,6 +12797,7 @@ packages: /json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} + hasBin: true /jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} @@ -11971,6 +12842,16 @@ packages: object.assign: 4.1.4 dev: true + /jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + dependencies: + array-includes: 3.1.7 + array.prototype.flat: 1.3.2 + object.assign: 4.1.5 + object.values: 1.1.7 + dev: true + /keyv@3.1.0: resolution: {integrity: sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==} dependencies: @@ -12020,8 +12901,9 @@ packages: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} dev: true - /language-tags@1.0.5: - resolution: {integrity: sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==} + /language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} dependencies: language-subtag-registry: 0.3.22 dev: true @@ -12093,7 +12975,7 @@ packages: dependencies: big.js: 5.2.2 emojis-list: 3.0.0 - json5: 1.0.1 + json5: 1.0.2 dev: true /loader-utils@1.4.2: @@ -12111,7 +12993,7 @@ packages: dependencies: big.js: 5.2.2 emojis-list: 3.0.0 - json5: 2.2.1 + json5: 2.2.3 dev: true /local-access@1.1.0: @@ -12141,13 +13023,6 @@ packages: p-locate: 5.0.0 dev: true - /locate-path@7.1.1: - resolution: {integrity: sha512-vJXaRMJgRVD3+cUZs3Mncj2mxpt5mP0EmNOsxRSZRMlbqjvxzDEOIUWXGmavo0ZC9+tNZCBLQ66reA11nbpHZg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - p-locate: 6.0.0 - dev: true - /lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} dev: false @@ -12230,6 +13105,11 @@ packages: engines: {node: '>=8'} dev: true + /lru-cache@10.1.0: + resolution: {integrity: sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==} + engines: {node: 14 || >=16.14} + dev: false + /lru-cache@4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} dependencies: @@ -12271,18 +13151,18 @@ packages: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} dependencies: - semver: 6.3.0 + semver: 6.3.1 dev: true - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + /make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + dependencies: + semver: 7.5.4 dev: true - /map-age-cleaner@0.1.3: - resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} - engines: {node: '>=6'} - dependencies: - p-defer: 1.0.0 + /make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} dev: true /map-cache@0.2.2: @@ -12338,14 +13218,6 @@ packages: engines: {node: '>= 0.6'} dev: true - /mem@9.0.2: - resolution: {integrity: sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==} - engines: {node: '>=12.20'} - dependencies: - map-age-cleaner: 0.1.3 - mimic-fn: 4.0.0 - dev: true - /memfs@3.4.7: resolution: {integrity: sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==} engines: {node: '>= 4.0.0'} @@ -12353,6 +13225,13 @@ packages: fs-monkey: 1.0.3 dev: true + /memoize@10.0.0: + resolution: {integrity: sha512-H6cBLgsi6vMWOcCpvVCdFFnl3kerEXbrYh9q+lY6VXvQSmM6CkmV08VOwT+WE2tzIEqRPFfAq3fm4v/UIW6mSA==} + engines: {node: '>=18'} + dependencies: + mimic-function: 5.0.0 + dev: true + /memory-fs@0.4.1: resolution: {integrity: sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==} dependencies: @@ -12452,6 +13331,11 @@ packages: engines: {node: '>=12'} dev: true + /mimic-function@5.0.0: + resolution: {integrity: sha512-RBfQ+9X9DpXdEoK7Bu+KeEU6vFhumEIiXKWECPzRBmDserEq4uR2b/VCm0LwpMSosoq2k+Zuxj/GzOr0Fn6h/g==} + engines: {node: '>=18'} + dev: true + /mimic-response@1.0.1: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} @@ -12518,34 +13402,32 @@ packages: engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 - dev: true /minimist@1.2.7: resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==} /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true /minipass-collect@1.0.2: resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} engines: {node: '>= 8'} dependencies: - minipass: 3.3.4 + minipass: 3.3.6 dev: true /minipass-flush@1.0.5: resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} engines: {node: '>= 8'} dependencies: - minipass: 3.3.4 + minipass: 3.3.6 dev: true /minipass-pipeline@1.2.4: resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} engines: {node: '>=8'} dependencies: - minipass: 3.3.4 + minipass: 3.3.6 dev: true /minipass@2.9.0: @@ -12555,13 +13437,23 @@ packages: yallist: 3.1.1 dev: true - /minipass@3.3.4: - resolution: {integrity: sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==} + /minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} dependencies: yallist: 4.0.0 dev: true + /minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + dev: true + + /minipass@7.0.4: + resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + engines: {node: '>=16 || 14 >=14.17'} + dev: false + /minizlib@1.3.3: resolution: {integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==} dependencies: @@ -12572,7 +13464,7 @@ packages: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} dependencies: - minipass: 3.3.4 + minipass: 3.3.6 yallist: 4.0.0 dev: true @@ -12616,6 +13508,7 @@ packages: /mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} + hasBin: true dev: true /mocha@9.2.2: @@ -12699,8 +13592,8 @@ packages: object-assign: 4.1.1 thenify-all: 1.6.0 - /nan@2.17.0: - resolution: {integrity: sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==} + /nan@2.18.0: + resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==} requiresBuild: true dev: true optional: true @@ -12718,6 +13611,12 @@ packages: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + /nanomatch@1.2.13: resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} engines: {node: '>=0.10.0'} @@ -12775,12 +13674,12 @@ packages: tslib: 2.6.2 dev: true - /node-abi@3.45.0: - resolution: {integrity: sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ==} + /node-abi@3.52.0: + resolution: {integrity: sha512-JJ98b02z16ILv7859irtXn4oUaFWADtvkzy2c0IAatNVX2Mc9Yoh8z6hZInn3QwvMEYhHuQloYi+TTQy67SIdQ==} engines: {node: '>=10'} requiresBuild: true dependencies: - semver: 7.3.8 + semver: 7.5.4 dev: false optional: true @@ -12796,11 +13695,28 @@ packages: whatwg-url: 5.0.0 dev: true + /node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: true + /node-forge@1.3.1: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} dev: true + /node-gyp-build@4.7.1: + resolution: {integrity: sha512-wTSrZ+8lsRRa3I3H8Xr65dLWSgCvY2l4AOnaeKdPA9TB/WYMPaTcrzf3rXvFoVvjKNVnu0CcWSx54qq9GKRUYg==} + hasBin: true + dev: true + /node-libs-browser@2.2.1: resolution: {integrity: sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==} dependencies: @@ -12839,6 +13755,14 @@ packages: /node-releases@2.0.10: resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} + /node-releases@2.0.13: + resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + dev: true + + /node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + dev: true + /nofilter@3.1.0: resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} engines: {node: '>=12.19'} @@ -12851,6 +13775,14 @@ packages: underscore: 1.6.0 dev: true + /nopt@5.0.0: + resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} + engines: {node: '>=6'} + hasBin: true + dependencies: + abbrev: 1.1.1 + dev: true + /normalize-path@2.1.1: resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} engines: {node: '>=0.10.0'} @@ -12898,6 +13830,15 @@ packages: path-key: 4.0.0 dev: true + /npmlog@5.0.1: + resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} + dependencies: + are-we-there-yet: 2.0.0 + console-control-strings: 1.1.0 + gauge: 3.0.2 + set-blocking: 2.0.0 + dev: true + /nth-check@1.0.2: resolution: {integrity: sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==} dependencies: @@ -12974,6 +13915,10 @@ packages: resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} dev: true + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true + /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -12996,6 +13941,16 @@ packages: object-keys: 1.1.1 dev: true + /object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: true + /object.entries@1.1.5: resolution: {integrity: sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==} engines: {node: '>= 0.4'} @@ -13005,6 +13960,15 @@ packages: es-abstract: 1.20.4 dev: true + /object.entries@1.1.7: + resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + /object.fromentries@2.0.5: resolution: {integrity: sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==} engines: {node: '>= 0.4'} @@ -13014,6 +13978,15 @@ packages: es-abstract: 1.20.4 dev: true + /object.fromentries@2.0.7: + resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + /object.getownpropertydescriptors@2.1.4: resolution: {integrity: sha512-sccv3L/pMModT6dJAYF3fzGMVcb38ysQ0tEE6ixv2yXJDtEIPph268OlAdJj5/qZMZDq2g/jqvwppt36uS/uQQ==} engines: {node: '>= 0.8'} @@ -13024,6 +13997,15 @@ packages: es-abstract: 1.20.4 dev: true + /object.groupby@1.0.1: + resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + dev: true + /object.hasown@1.1.1: resolution: {integrity: sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==} dependencies: @@ -13031,6 +14013,13 @@ packages: es-abstract: 1.20.4 dev: true + /object.hasown@1.1.3: + resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} + dependencies: + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + /object.omit@3.0.0: resolution: {integrity: sha512-EO+BCv6LJfu+gBIF3ggLicFebFLN5zqzz/WWJlMFfkMyGth+oBkhxzDl0wx2W4GkLzuQs/FsSkXZb2IMWQqmBQ==} engines: {node: '>=0.10.0'} @@ -13054,6 +14043,15 @@ packages: es-abstract: 1.20.4 dev: true + /object.values@1.1.7: + resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + /obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} dev: true @@ -13173,18 +14171,6 @@ packages: engines: {node: '>=6'} dev: true - /p-defer@1.0.0: - resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} - engines: {node: '>=4'} - dev: true - - /p-event@5.0.1: - resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - p-timeout: 5.1.0 - dev: true - /p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -13199,13 +14185,6 @@ packages: yocto-queue: 0.1.0 dev: true - /p-limit@4.0.0: - resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - yocto-queue: 1.0.0 - dev: true - /p-locate@3.0.0: resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} engines: {node: '>=6'} @@ -13227,13 +14206,6 @@ packages: p-limit: 3.1.0 dev: true - /p-locate@6.0.0: - resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - p-limit: 4.0.0 - dev: true - /p-map@3.0.0: resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} engines: {node: '>=8'} @@ -13248,11 +14220,9 @@ packages: aggregate-error: 3.1.0 dev: true - /p-map@5.5.0: - resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==} - engines: {node: '>=12'} - dependencies: - aggregate-error: 4.0.1 + /p-map@6.0.0: + resolution: {integrity: sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==} + engines: {node: '>=16'} dev: true /p-retry@4.6.2: @@ -13263,16 +14233,19 @@ packages: retry: 0.13.1 dev: true - /p-timeout@5.1.0: - resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} - engines: {node: '>=12'} - dev: true - /p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} dev: true + /package-config@5.0.0: + resolution: {integrity: sha512-GYTTew2slBcYdvRHqjhwaaydVMvn/qrGC323+nKclYioNSLTDUM/lGgtGTgyHVtYcozb+XkE8CNhwcraOmZ9Mg==} + engines: {node: '>=18'} + dependencies: + find-up-simple: 1.0.0 + load-json-file: 7.0.1 + dev: true + /package-hash@4.0.0: resolution: {integrity: sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==} engines: {node: '>=8'} @@ -13290,7 +14263,7 @@ packages: got: 9.6.0 registry-auth-token: 4.2.2 registry-url: 5.1.0 - semver: 6.3.0 + semver: 6.3.1 dev: true /pako@1.0.11: @@ -13347,17 +14320,12 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: - '@babel/code-frame': 7.21.4 + '@babel/code-frame': 7.23.5 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 dev: true - /parse-ms@2.1.0: - resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==} - engines: {node: '>=6'} - dev: true - /parse-ms@3.0.0: resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} engines: {node: '>=12'} @@ -13408,11 +14376,6 @@ packages: engines: {node: '>=8'} dev: true - /path-exists@5.0.0: - resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: true - /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -13420,7 +14383,6 @@ packages: /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - dev: true /path-key@4.0.0: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} @@ -13430,6 +14392,14 @@ packages: /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + /path-scurry@1.10.1: + resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + lru-cache: 10.1.0 + minipass: 7.0.4 + dev: false + /path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} dev: true @@ -13439,6 +14409,11 @@ packages: engines: {node: '>=8'} dev: true + /path-type@5.0.0: + resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} + engines: {node: '>=12'} + dev: true + /pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} dev: true @@ -13469,6 +14444,11 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + /picomatch@3.0.1: + resolution: {integrity: sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==} + engines: {node: '>=10'} + dev: true + /pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -13482,14 +14462,6 @@ packages: resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} engines: {node: '>= 6'} - /pkg-conf@4.0.0: - resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - find-up: 6.3.0 - load-json-file: 7.0.1 - dev: true - /pkg-dir@3.0.0: resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} engines: {node: '>=6'} @@ -13508,7 +14480,7 @@ packages: resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: - irregular-plurals: 3.3.0 + irregular-plurals: 3.5.0 dev: true /pn@1.1.0: @@ -13591,7 +14563,7 @@ packages: resolution: {integrity: sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==} engines: {node: '>=6.9.0'} dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 color: 3.2.1 has: 1.0.3 postcss: 7.0.39 @@ -13604,7 +14576,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 caniuse-api: 3.0.0 colord: 2.9.3 postcss: 8.4.23 @@ -13625,7 +14597,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 postcss: 8.4.23 postcss-value-parser: 4.2.0 dev: true @@ -13759,7 +14731,7 @@ packages: loader-utils: 2.0.3 postcss: 8.4.23 schema-utils: 3.1.1 - semver: 7.3.8 + semver: 7.5.4 webpack: 4.46.0 dev: true @@ -13788,7 +14760,7 @@ packages: resolution: {integrity: sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==} engines: {node: '>=6.9.0'} dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 caniuse-api: 3.0.0 cssnano-util-same-parent: 4.0.1 postcss: 7.0.39 @@ -13802,7 +14774,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 caniuse-api: 3.0.0 cssnano-utils: 3.1.0(postcss@8.4.23) postcss: 8.4.23 @@ -13854,7 +14826,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: alphanum-sort: 1.0.2 - browserslist: 4.21.5 + browserslist: 4.22.1 cssnano-util-get-arguments: 4.0.0 postcss: 7.0.39 postcss-value-parser: 3.3.1 @@ -13867,7 +14839,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 cssnano-utils: 3.1.0(postcss@8.4.23) postcss: 8.4.23 postcss-value-parser: 4.2.0 @@ -14060,7 +15032,7 @@ packages: resolution: {integrity: sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==} engines: {node: '>=6.9.0'} dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 postcss: 7.0.39 postcss-value-parser: 3.3.1 dev: true @@ -14071,7 +15043,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 postcss: 8.4.23 postcss-value-parser: 4.2.0 dev: true @@ -14139,7 +15111,7 @@ packages: resolution: {integrity: sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==} engines: {node: '>=6.9.0'} dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 caniuse-api: 3.0.0 has: 1.0.3 postcss: 7.0.39 @@ -14151,7 +15123,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 caniuse-api: 3.0.0 postcss: 8.4.23 dev: true @@ -14273,6 +15245,15 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 + /postcss@8.4.32: + resolution: {integrity: sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + /preact-cli@3.4.1(preact-render-to-string@5.2.6)(preact@10.11.3): resolution: {integrity: sha512-/4be0PuBmAIAox9u8GLJublFpEymq7Lk4JW4PEPz9ErFH/ncZf/oBPhECtXGq9IPqNOEe4r2l8sA+3uqKVwBfw==} engines: {node: '>=12'} @@ -14324,7 +15305,7 @@ packages: fork-ts-checker-webpack-plugin: 4.1.6(typescript@4.6.4)(webpack@4.46.0) get-port: 5.1.1 gittar: 0.1.1 - glob: 8.0.3 + glob: 8.1.0 html-webpack-exclude-assets-plugin: 0.0.7 html-webpack-plugin: 3.2.0(webpack@4.46.0) ip: 1.1.8 @@ -14416,10 +15397,10 @@ packages: detect-libc: 2.0.2 expand-template: 2.0.3 github-from-package: 0.0.0 - minimist: 1.2.7 + minimist: 1.2.8 mkdirp-classic: 0.5.3 napi-build-utils: 1.0.2 - node-abi: 3.45.0 + node-abi: 3.52.0 pump: 3.0.0 rc: 1.2.8 simple-get: 4.0.1 @@ -14443,9 +15424,10 @@ packages: engines: {node: '>=4'} dev: true - /prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} + /prettier@3.1.1: + resolution: {integrity: sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==} + engines: {node: '>=14'} + hasBin: true dev: true /pretty-bytes@4.0.2: @@ -14481,13 +15463,6 @@ packages: engines: {node: '>= 0.8'} dev: true - /pretty-ms@7.0.1: - resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} - engines: {node: '>=10'} - dependencies: - parse-ms: 2.1.0 - dev: true - /pretty-ms@8.0.0: resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} engines: {node: '>=14.16'} @@ -14601,6 +15576,7 @@ packages: /pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + requiresBuild: true dependencies: end-of-stream: 1.4.4 once: 1.4.0 @@ -14712,6 +15688,7 @@ packages: /rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true + requiresBuild: true dependencies: deep-extend: 0.6.0 ini: 1.3.8 @@ -14781,6 +15758,7 @@ packages: /readable-stream@3.6.0: resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} engines: {node: '>= 6'} + requiresBuild: true dependencies: inherits: 2.0.4 string_decoder: 1.3.0 @@ -14793,7 +15771,6 @@ packages: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 - dev: true /readdirp@2.2.1: resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==} @@ -14814,6 +15791,18 @@ packages: dependencies: picomatch: 2.3.1 + /reflect.getprototypeof@1.0.4: + resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + globalthis: 1.0.3 + which-builtin-type: 1.1.3 + dev: true + /regenerate-unicode-properties@10.1.0: resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==} engines: {node: '>=4'} @@ -14828,14 +15817,12 @@ packages: /regenerator-runtime@0.13.10: resolution: {integrity: sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==} - /regenerator-transform@0.15.0: - resolution: {integrity: sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==} - dependencies: - '@babel/runtime': 7.19.4 + /regenerator-runtime@0.14.0: + resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} dev: true - /regenerator-transform@0.15.1: - resolution: {integrity: sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==} + /regenerator-transform@0.15.2: + resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} dependencies: '@babel/runtime': 7.19.4 dev: true @@ -14857,23 +15844,20 @@ packages: functions-have-names: 1.2.3 dev: true + /regexp.prototype.flags@1.5.1: + resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + set-function-name: 2.0.1 + dev: true + /regexpp@3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} dev: true - /regexpu-core@5.2.1: - resolution: {integrity: sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==} - engines: {node: '>=4'} - dependencies: - regenerate: 1.4.2 - regenerate-unicode-properties: 10.1.0 - regjsgen: 0.7.1 - regjsparser: 0.9.1 - unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.0.0 - dev: true - /regexpu-core@5.3.2: resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} engines: {node: '>=4'} @@ -14900,12 +15884,9 @@ packages: rc: 1.2.8 dev: true - /regjsgen@0.7.1: - resolution: {integrity: sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==} - dev: true - /regjsparser@0.9.1: resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} + hasBin: true dependencies: jsesc: 0.5.0 dev: true @@ -15055,21 +16036,22 @@ packages: deprecated: https://github.com/lydell/resolve-url#deprecated dev: true - /resolve@1.22.1: - resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} + /resolve@1.22.2: + resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} + hasBin: true dependencies: is-core-module: 2.11.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: true - /resolve@1.22.2: - resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true dependencies: - is-core-module: 2.11.0 + is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + dev: true /resolve@2.0.0-next.4: resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} @@ -15079,6 +16061,15 @@ packages: supports-preserve-symlinks-flag: 1.0.0 dev: true + /resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + /responselike@1.0.2: resolution: {integrity: sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==} dependencies: @@ -15140,7 +16131,7 @@ packages: peerDependencies: rollup: ^2.0.0 dependencies: - '@babel/code-frame': 7.21.4 + '@babel/code-frame': 7.23.5 jest-worker: 26.6.2 rollup: 2.79.1 serialize-javascript: 4.0.0 @@ -15169,7 +16160,17 @@ packages: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} dependencies: - mri: 1.2.0 + mri: 1.2.0 + dev: true + + /safe-array-concat@1.0.1: + resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + isarray: 2.0.5 dev: true /safe-buffer@5.1.2: @@ -15178,6 +16179,7 @@ packages: /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + requiresBuild: true /safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} @@ -15288,7 +16290,7 @@ packages: resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==} engines: {node: '>=8'} dependencies: - semver: 6.3.0 + semver: 6.3.1 dev: true /semver@5.7.2: @@ -15299,6 +16301,11 @@ packages: /semver@6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: true + /semver@7.3.5: resolution: {integrity: sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==} engines: {node: '>=10'} @@ -15309,6 +16316,16 @@ packages: /semver@7.3.8: resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + requiresBuild: true dependencies: lru-cache: 6.0.0 @@ -15389,6 +16406,25 @@ packages: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true + /set-function-length@1.1.1: + resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /set-function-name@2.0.1: + resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.1 + dev: true + /set-value@2.0.1: resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} engines: {node: '>=0.10.0'} @@ -15438,7 +16474,6 @@ packages: engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 - dev: true /shebang-regex@1.0.0: resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} @@ -15448,10 +16483,9 @@ packages: /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - dev: true - /shiki@0.14.4: - resolution: {integrity: sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==} + /shiki@0.14.6: + resolution: {integrity: sha512-R4koBBlQP33cC8cpzX0hAoOURBHJILp4Aaduh2eYi+Vj8ZBqtK/5SWNEHBS3qwUMu8dqOtI/ftno3ESfNeVW9g==} dependencies: ansi-sequence-parser: 1.1.1 jsonc-parser: 3.2.0 @@ -15474,7 +16508,6 @@ packages: /signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - dev: true /simple-concat@1.0.1: resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} @@ -15563,6 +16596,11 @@ packages: engines: {node: '>=14.16'} dev: true + /slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + dev: true + /slice-ansi@4.0.0: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} engines: {node: '>=10'} @@ -15750,7 +16788,7 @@ packages: resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} engines: {node: '>= 8'} dependencies: - minipass: 3.3.4 + minipass: 3.3.6 dev: true /stable@0.1.8: @@ -15761,13 +16799,6 @@ packages: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} dev: true - /stack-utils@2.0.5: - resolution: {integrity: sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==} - engines: {node: '>=10'} - dependencies: - escape-string-regexp: 2.0.0 - dev: true - /stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -15833,7 +16864,6 @@ packages: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true /string-width@5.1.2: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} @@ -15842,6 +16872,29 @@ packages: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.0.1 + dev: false + + /string-width@7.0.0: + resolution: {integrity: sha512-GPQHj7row82Hjo9hKZieKcHIhaAIKOJvFSIZXuCU9OASVZrMNUaZuz++SPVrBjnLsnk4k+z9f2EIypgxf2vNFw==} + engines: {node: '>=18'} + dependencies: + emoji-regex: 10.3.0 + get-east-asian-width: 1.2.0 + strip-ansi: 7.1.0 + dev: true + + /string.prototype.matchall@4.0.10: + resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + internal-slot: 1.0.6 + regexp.prototype.flags: 1.5.1 + set-function-name: 2.0.1 + side-channel: 1.0.4 dev: true /string.prototype.matchall@4.0.7: @@ -15857,6 +16910,15 @@ packages: side-channel: 1.0.4 dev: true + /string.prototype.trim@1.2.8: + resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + /string.prototype.trimend@1.0.5: resolution: {integrity: sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==} dependencies: @@ -15865,6 +16927,14 @@ packages: es-abstract: 1.20.4 dev: true + /string.prototype.trimend@1.0.7: + resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + /string.prototype.trimstart@1.0.5: resolution: {integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==} dependencies: @@ -15873,6 +16943,14 @@ packages: es-abstract: 1.20.4 dev: true + /string.prototype.trimstart@1.0.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + /string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: @@ -15881,6 +16959,7 @@ packages: /string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + requiresBuild: true dependencies: safe-buffer: 5.2.1 @@ -15910,14 +16989,19 @@ packages: engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 - dev: true /strip-ansi@7.0.1: resolution: {integrity: sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==} engines: {node: '>=12'} dependencies: ansi-regex: 6.0.1 - dev: true + dev: false + + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} @@ -15969,7 +17053,7 @@ packages: resolution: {integrity: sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==} engines: {node: '>=6.9.0'} dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 postcss: 7.0.39 postcss-selector-parser: 3.1.2 dev: true @@ -15980,7 +17064,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 postcss: 8.4.23 postcss-selector-parser: 6.0.12 dev: true @@ -16009,7 +17093,7 @@ packages: indent-string: 5.0.0 js-yaml: 3.14.1 serialize-error: 7.0.1 - strip-ansi: 7.0.1 + strip-ansi: 7.1.0 dev: true /supports-color@5.5.0: @@ -16048,7 +17132,7 @@ packages: csso: 4.2.0 js-yaml: 3.14.1 mkdirp: 0.5.6 - object.values: 1.1.5 + object.values: 1.1.7 sax: 1.2.4 stable: 0.1.8 unquote: 1.1.1 @@ -16163,7 +17247,7 @@ packages: end-of-stream: 1.4.4 fs-constants: 1.0.0 inherits: 2.0.4 - readable-stream: 3.6.0 + readable-stream: 3.6.2 dev: false optional: true @@ -16186,7 +17270,19 @@ packages: dependencies: chownr: 2.0.0 fs-minipass: 2.1.0 - minipass: 3.3.4 + minipass: 3.3.6 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + dev: true + + /tar@6.2.0: + resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==} + engines: {node: '>=10'} + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 minizlib: 2.1.2 mkdirp: 1.0.4 yallist: 4.0.0 @@ -16230,6 +17326,24 @@ packages: worker-farm: 1.7.0 dev: true + /terser-webpack-plugin@1.4.5(webpack@4.47.0): + resolution: {integrity: sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==} + engines: {node: '>= 6.9.0'} + peerDependencies: + webpack: ^4.0.0 + dependencies: + cacache: 12.0.4 + find-cache-dir: 2.1.0 + is-wsl: 1.1.0 + schema-utils: 1.0.0 + serialize-javascript: 4.0.0 + source-map: 0.6.1 + terser: 4.8.1 + webpack: 4.47.0 + webpack-sources: 1.4.3 + worker-farm: 1.7.0 + dev: true + /terser-webpack-plugin@4.2.3(webpack@4.46.0): resolution: {integrity: sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==} engines: {node: '>= 10.13.0'} @@ -16271,13 +17385,13 @@ packages: source-map-support: 0.5.21 dev: true - /terser@5.19.4: - resolution: {integrity: sha512-6p1DjHeuluwxDXcuT9VR8p64klWJKo1ILiy19s6C9+0Bh2+NWTX6nD9EPppiER4ICkHDVB1RkVpin/YW2nQn/g==} + /terser@5.26.0: + resolution: {integrity: sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==} engines: {node: '>=10'} hasBin: true dependencies: '@jridgewell/source-map': 0.3.5 - acorn: 8.10.0 + acorn: 8.11.2 commander: 2.20.3 source-map-support: 0.5.21 dev: true @@ -16437,10 +17551,10 @@ packages: resolution: {integrity: sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==} engines: {node: '>=8'} dependencies: - tslib: 2.6.1 + tslib: 2.6.2 dev: true - /ts-node@10.9.1(@types/node@20.5.9)(typescript@5.2.2): + /ts-node@10.9.1(@types/node@20.10.4)(typescript@5.3.3): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -16459,14 +17573,14 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.3 - '@types/node': 20.5.9 + '@types/node': 20.10.4 acorn: 8.8.1 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.2.2 + typescript: 5.3.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 dev: true @@ -16483,12 +17597,12 @@ packages: typescript: 4.6.4 dev: true - /tsconfig-paths@3.14.1: - resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} dependencies: '@types/json5': 0.0.29 - json5: 1.0.1 - minimist: 1.2.7 + json5: 1.0.2 + minimist: 1.2.8 strip-bom: 3.0.0 dev: true @@ -16496,29 +17610,17 @@ packages: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true - /tslib@2.5.3: - resolution: {integrity: sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==} - - /tslib@2.6.0: - resolution: {integrity: sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==} - dev: false - - /tslib@2.6.1: - resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==} - dev: true - /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - dev: true - /tsutils@3.21.0(typescript@5.2.2): + /tsutils@3.21.0(typescript@5.3.3): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 5.2.2 + typescript: 5.3.3 dev: true /tty-browserify@0.0.0: @@ -16527,6 +17629,7 @@ packages: /tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + requiresBuild: true dependencies: safe-buffer: 5.2.1 @@ -16581,6 +17684,44 @@ packages: mime-types: 2.1.35 dev: true + /typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + is-typed-array: 1.1.12 + dev: true + /typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} dependencies: @@ -16591,18 +17732,18 @@ packages: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} dev: true - /typedoc@0.25.1(typescript@5.2.2): - resolution: {integrity: sha512-c2ye3YUtGIadxN2O6YwPEXgrZcvhlZ6HlhWZ8jQRNzwLPn2ylhdGqdR8HbyDRyALP8J6lmSANILCkkIdNPFxqA==} + /typedoc@0.25.4(typescript@5.3.3): + resolution: {integrity: sha512-Du9ImmpBCw54bX275yJrxPVnjdIyJO/84co0/L9mwe0R3G4FSR6rQ09AlXVRvZEGMUg09+z/usc8mgygQ1aidA==} engines: {node: '>= 16'} hasBin: true peerDependencies: - typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x + typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x dependencies: lunr: 2.3.9 marked: 4.3.0 minimatch: 9.0.3 - shiki: 0.14.4 - typescript: 5.2.2 + shiki: 0.14.6 + typescript: 5.3.3 dev: true /typescript@4.6.4: @@ -16611,8 +17752,8 @@ packages: hasBin: true dev: true - /typescript@5.2.2: - resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + /typescript@5.3.3: + resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} engines: {node: '>=14.17'} hasBin: true dev: true @@ -16638,6 +17779,10 @@ packages: resolution: {integrity: sha512-z4o1fvKUojIWh9XuaVLUDdf86RQiq13AC1dmHbTpoyuu+bquHms76v16CjycCbec87J7z0k//SiQVk0sMdFmpQ==} dev: true + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true + /unfetch@4.2.0: resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} dev: true @@ -16655,11 +17800,6 @@ packages: unicode-property-aliases-ecmascript: 2.1.0 dev: true - /unicode-match-property-value-ecmascript@2.0.0: - resolution: {integrity: sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==} - engines: {node: '>=4'} - dev: true - /unicode-match-property-value-ecmascript@2.1.0: resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} engines: {node: '>=4'} @@ -16670,6 +17810,11 @@ packages: engines: {node: '>=4'} dev: true + /unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + dev: true + /union-value@1.0.1: resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} engines: {node: '>=0.10.0'} @@ -16735,26 +17880,48 @@ packages: requiresBuild: true dev: true - /update-browserslist-db@1.0.10(browserslist@4.21.4): + /update-browserslist-db@1.0.10(browserslist@4.21.5): resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: + browserslist: 4.21.5 + escalade: 3.1.1 + picocolors: 1.0.0 + + /update-browserslist-db@1.0.13(browserslist@4.21.4): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: browserslist: 4.21.4 escalade: 3.1.1 picocolors: 1.0.0 dev: true - /update-browserslist-db@1.0.10(browserslist@4.21.5): - resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} + /update-browserslist-db@1.0.13(browserslist@4.22.1): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 escalade: 3.1.1 picocolors: 1.0.0 + dev: true + + /update-browserslist-db@1.0.13(browserslist@4.22.2): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.22.2 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: true /update-notifier@5.1.0: resolution: {integrity: sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==} @@ -16771,7 +17938,7 @@ packages: is-yarn-global: 0.3.0 latest-version: 5.1.0 pupa: 2.1.1 - semver: 7.3.8 + semver: 7.5.4 semver-diff: 3.1.1 xdg-basedir: 4.0.0 dev: true @@ -16836,6 +18003,7 @@ packages: /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + requiresBuild: true /util.promisify@1.0.0: resolution: {integrity: sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==} @@ -16847,8 +18015,8 @@ packages: /util.promisify@1.0.1: resolution: {integrity: sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==} dependencies: - define-properties: 1.1.4 - es-abstract: 1.20.4 + define-properties: 1.2.1 + es-abstract: 1.22.3 has-symbols: 1.0.3 object.getownpropertydescriptors: 2.1.4 dev: true @@ -16856,8 +18024,8 @@ packages: /util.promisify@1.1.1: resolution: {integrity: sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw==} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 + call-bind: 1.0.5 + define-properties: 1.2.1 for-each: 0.3.3 has-symbols: 1.0.3 object.getownpropertydescriptors: 2.1.4 @@ -16900,13 +18068,13 @@ packages: resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} dev: true - /v8-to-istanbul@9.0.1: - resolution: {integrity: sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==} + /v8-to-istanbul@9.2.0: + resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} engines: {node: '>=10.12.0'} dependencies: - '@jridgewell/trace-mapping': 0.3.17 - '@types/istanbul-lib-coverage': 2.0.4 - convert-source-map: 1.9.0 + '@jridgewell/trace-mapping': 0.3.20 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 dev: true /validate-npm-package-name@4.0.0: @@ -16998,6 +18166,11 @@ packages: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} dev: true + /webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + dev: true + /webpack-bundle-analyzer@4.6.1: resolution: {integrity: sha512-oKz9Oz9j3rUciLNfpGFjOb49/jEpXNmWdVH8Ls//zNcnLlQdTGXQQMsBbb/gR7Zl8WNLxVCq+0Hqbx3zv6twBw==} engines: {node: '>= 10.13.0'} @@ -17169,6 +18342,46 @@ packages: - supports-color dev: true + /webpack@4.47.0: + resolution: {integrity: sha512-td7fYwgLSrky3fI1EuU5cneU4+pbH6GgOfuKNS1tNPcfdGinGELAqsb/BP4nnvZyKSG2i/xFGU7+n2PvZA8HJQ==} + engines: {node: '>=6.11.5'} + hasBin: true + peerDependencies: + webpack-cli: '*' + webpack-command: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + webpack-command: + optional: true + dependencies: + '@webassemblyjs/ast': 1.9.0 + '@webassemblyjs/helper-module-context': 1.9.0 + '@webassemblyjs/wasm-edit': 1.9.0 + '@webassemblyjs/wasm-parser': 1.9.0 + acorn: 6.4.2 + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + chrome-trace-event: 1.0.3 + enhanced-resolve: 4.5.0 + eslint-scope: 4.0.3 + json-parse-better-errors: 1.0.2 + loader-runner: 2.4.0 + loader-utils: 1.4.2 + memory-fs: 0.4.1 + micromatch: 3.1.10 + mkdirp: 0.5.6 + neo-async: 2.6.2 + node-libs-browser: 2.2.1 + schema-utils: 1.0.0 + tapable: 1.1.3 + terser-webpack-plugin: 1.4.5(webpack@4.47.0) + watchpack: 1.7.5 + webpack-sources: 1.4.3 + transitivePeerDependencies: + - supports-color + dev: true + /websocket-driver@0.7.4: resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} engines: {node: '>=0.8.0'} @@ -17194,10 +18407,22 @@ packages: iconv-lite: 0.4.24 dev: true + /whatwg-encoding@2.0.0: + resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} + engines: {node: '>=12'} + dependencies: + iconv-lite: 0.6.3 + dev: true + /whatwg-mimetype@2.3.0: resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==} dev: true + /whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + dev: true + /whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} dependencies: @@ -17223,10 +18448,48 @@ packages: is-symbol: 1.0.4 dev: true + /which-builtin-type@1.1.3: + resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} + engines: {node: '>= 0.4'} + dependencies: + function.prototype.name: 1.1.6 + has-tostringtag: 1.0.0 + is-async-function: 2.0.0 + is-date-object: 1.0.5 + is-finalizationregistry: 1.0.2 + is-generator-function: 1.0.10 + is-regex: 1.1.4 + is-weakref: 1.0.2 + isarray: 2.0.5 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.1 + which-typed-array: 1.1.13 + dev: true + + /which-collection@1.0.1: + resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} + dependencies: + is-map: 2.0.2 + is-set: 2.0.2 + is-weakmap: 2.0.1 + is-weakset: 2.0.2 + dev: true + /which-module@2.0.0: resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==} dev: true + /which-typed-array@1.1.13: + resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + dev: true + /which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -17239,6 +18502,11 @@ packages: engines: {node: '>= 8'} dependencies: isexe: 2.0.0 + + /wide-align@1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + dependencies: + string-width: 4.2.3 dev: true /widest-line@3.1.0: @@ -17276,7 +18544,7 @@ packages: dependencies: '@apideck/better-ajv-errors': 0.3.6(ajv@8.11.0) '@babel/core': 7.18.9 - '@babel/preset-env': 7.19.4(@babel/core@7.18.9) + '@babel/preset-env': 7.23.5(@babel/core@7.18.9) '@babel/runtime': 7.19.4 '@rollup/plugin-babel': 5.3.1(@babel/core@7.18.9)(rollup@2.79.1) '@rollup/plugin-node-resolve': 11.2.1(rollup@2.79.1) @@ -17452,7 +18720,15 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true + + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: false /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -17466,14 +18742,6 @@ packages: typedarray-to-buffer: 3.1.5 dev: true - /write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - dependencies: - imurmurhash: 0.1.4 - signal-exit: 3.0.7 - dev: true - /write-file-atomic@5.0.1: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -17645,19 +18913,6 @@ packages: yargs-parser: 20.2.9 dev: true - /yargs@17.6.0: - resolution: {integrity: sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==} - engines: {node: '>=12'} - dependencies: - cliui: 8.0.1 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - dev: true - /yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -17681,11 +18936,6 @@ packages: engines: {node: '>=10'} dev: true - /yocto-queue@1.0.0: - resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} - engines: {node: '>=12.20'} - dev: true - /yup@0.32.11: resolution: {integrity: sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==} engines: {node: '>=10'}