diff --git a/apps/consent/app/graphql/generated.ts b/apps/consent/app/graphql/generated.ts index c355da8406..3958a65f86 100644 --- a/apps/consent/app/graphql/generated.ts +++ b/apps/consent/app/graphql/generated.ts @@ -449,6 +449,14 @@ export type CurrencyConversionEstimation = { readonly usdCentAmount: Scalars['CentAmount']['output']; }; +export type Delegation = { + readonly __typename: 'Delegation'; + readonly app: Scalars['String']['output']; + readonly handledAt: Scalars['Timestamp']['output']; + readonly remember: Scalars['Boolean']['output']; + readonly scope: ReadonlyArray; +}; + export type DepositFeesInformation = { readonly __typename: 'DepositFeesInformation'; readonly minBankFee: Scalars['String']['output']; @@ -877,6 +885,13 @@ export type MerchantPayload = { readonly merchant?: Maybe; }; +export type MobileSession = { + readonly __typename: 'MobileSession'; + readonly expiresAt: Scalars['Timestamp']['output']; + readonly id: Scalars['ID']['output']; + readonly issuedAt: Scalars['Timestamp']['output']; +}; + export type MobileVersions = { readonly __typename: 'MobileVersions'; readonly currentSupported: Scalars['Int']['output']; @@ -1914,6 +1929,8 @@ export type User = { readonly contacts: ReadonlyArray; readonly createdAt: Scalars['Timestamp']['output']; readonly defaultAccount: Account; + /** List of Oauth2 delegations */ + readonly delegations: ReadonlyArray; /** Email address */ readonly email?: Maybe; readonly id: Scalars['ID']['output']; @@ -1922,6 +1939,8 @@ export type User = { * When value is 'default' the intent is to use preferred language from OS settings. */ readonly language: Scalars['Language']['output']; + /** List of mobile sessions */ + readonly mobileSessions: ReadonlyArray; /** Phone number with international calling code. */ readonly phone?: Maybe; readonly supportChat: ReadonlyArray; diff --git a/apps/dashboard/cypress/e2e/consent-integration.cy.ts b/apps/dashboard/cypress/e2e/consent-integration.cy.ts index 1f16fb1b18..08e9d9b023 100644 --- a/apps/dashboard/cypress/e2e/consent-integration.cy.ts +++ b/apps/dashboard/cypress/e2e/consent-integration.cy.ts @@ -32,22 +32,6 @@ describe("Consent integration Test", () => { cy.get("[data-testid=verification_code_input]").should("not.be.disabled") cy.get("[data-testid=verification_code_input]").type(code) - cy.contains("label", "read").should("exist") - cy.contains("label", "read").should("be.visible") - cy.contains("label", "read").should("not.be.disabled") - cy.contains("label", "read").should("not.be.disabled") - cy.contains("label", "read").click() - - cy.contains("label", "write").should("exist") - cy.contains("label", "write").should("be.visible") - cy.contains("label", "write").should("not.be.disabled") - cy.contains("label", "write").click() - - cy.get("[data-testid=submit_consent_btn]").should("exist") - cy.get("[data-testid=submit_consent_btn]").should("be.visible") - cy.get("[data-testid=submit_consent_btn]").should("not.be.disabled") - cy.get("[data-testid=submit_consent_btn]").click() - cy.url().should("eq", Cypress.config().baseUrl + "/") cy.getCookie("next-auth.session-token").then((cookie) => { if (cookie && cookie.value) { diff --git a/apps/dashboard/services/graphql/generated.ts b/apps/dashboard/services/graphql/generated.ts index a243655abd..97685a0279 100644 --- a/apps/dashboard/services/graphql/generated.ts +++ b/apps/dashboard/services/graphql/generated.ts @@ -489,6 +489,14 @@ export type CurrencyConversionEstimation = { readonly usdCentAmount: Scalars['CentAmount']['output']; }; +export type Delegation = { + readonly __typename: 'Delegation'; + readonly app: Scalars['String']['output']; + readonly handledAt: Scalars['Timestamp']['output']; + readonly remember: Scalars['Boolean']['output']; + readonly scope: ReadonlyArray; +}; + export type DepositFeesInformation = { readonly __typename: 'DepositFeesInformation'; readonly minBankFee: Scalars['String']['output']; @@ -917,6 +925,13 @@ export type MerchantPayload = { readonly merchant?: Maybe; }; +export type MobileSession = { + readonly __typename: 'MobileSession'; + readonly expiresAt: Scalars['Timestamp']['output']; + readonly id: Scalars['ID']['output']; + readonly issuedAt: Scalars['Timestamp']['output']; +}; + export type MobileVersions = { readonly __typename: 'MobileVersions'; readonly currentSupported: Scalars['Int']['output']; @@ -2011,6 +2026,8 @@ export type User = { readonly contacts: ReadonlyArray; readonly createdAt: Scalars['Timestamp']['output']; readonly defaultAccount: Account; + /** List of Oauth2 delegations */ + readonly delegations: ReadonlyArray; /** Email address */ readonly email?: Maybe; readonly id: Scalars['ID']['output']; @@ -2019,6 +2036,8 @@ export type User = { * When value is 'default' the intent is to use preferred language from OS settings. */ readonly language: Scalars['Language']['output']; + /** List of mobile sessions */ + readonly mobileSessions: ReadonlyArray; /** Phone number with international calling code. */ readonly phone?: Maybe; readonly statefulNotifications: StatefulNotificationConnection; @@ -3462,6 +3481,7 @@ export type ResolversTypes = { CountryCode: ResolverTypeWrapper; Currency: ResolverTypeWrapper; CurrencyConversionEstimation: ResolverTypeWrapper; + Delegation: ResolverTypeWrapper; DepositFeesInformation: ResolverTypeWrapper; DeviceNotificationTokenCreateInput: DeviceNotificationTokenCreateInput; DisplayCurrency: ResolverTypeWrapper; @@ -3527,6 +3547,7 @@ export type ResolversTypes = { MerchantMapSuggestInput: MerchantMapSuggestInput; MerchantPayload: ResolverTypeWrapper; Minutes: ResolverTypeWrapper; + MobileSession: ResolverTypeWrapper; MobileVersions: ResolverTypeWrapper; Mutation: ResolverTypeWrapper<{}>; MyUpdatesPayload: ResolverTypeWrapper & { update?: Maybe }>; @@ -3689,6 +3710,7 @@ export type ResolversParentTypes = { CountryCode: Scalars['CountryCode']['output']; Currency: Currency; CurrencyConversionEstimation: CurrencyConversionEstimation; + Delegation: Delegation; DepositFeesInformation: DepositFeesInformation; DeviceNotificationTokenCreateInput: DeviceNotificationTokenCreateInput; DisplayCurrency: Scalars['DisplayCurrency']['output']; @@ -3752,6 +3774,7 @@ export type ResolversParentTypes = { MerchantMapSuggestInput: MerchantMapSuggestInput; MerchantPayload: MerchantPayload; Minutes: Scalars['Minutes']['output']; + MobileSession: MobileSession; MobileVersions: MobileVersions; Mutation: {}; MyUpdatesPayload: Omit & { update?: Maybe }; @@ -4128,6 +4151,14 @@ export type CurrencyConversionEstimationResolvers; }; +export type DelegationResolvers = { + app?: Resolver; + handledAt?: Resolver; + remember?: Resolver; + scope?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}; + export type DepositFeesInformationResolvers = { minBankFee?: Resolver; minBankFeeThreshold?: Resolver; @@ -4360,6 +4391,13 @@ export interface MinutesScalarConfig extends GraphQLScalarTypeConfig = { + expiresAt?: Resolver; + id?: Resolver; + issuedAt?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}; + export type MobileVersionsResolvers = { currentSupported?: Resolver; minSupported?: Resolver; @@ -4817,9 +4855,11 @@ export type UserResolvers, ParentType, ContextType>; createdAt?: Resolver; defaultAccount?: Resolver; + delegations?: Resolver, ParentType, ContextType>; email?: Resolver, ParentType, ContextType>; id?: Resolver; language?: Resolver; + mobileSessions?: Resolver, ParentType, ContextType>; phone?: Resolver, ParentType, ContextType>; statefulNotifications?: Resolver>; supportChat?: Resolver, ParentType, ContextType>; @@ -4973,6 +5013,7 @@ export type Resolvers = { CountryCode?: GraphQLScalarType; Currency?: CurrencyResolvers; CurrencyConversionEstimation?: CurrencyConversionEstimationResolvers; + Delegation?: DelegationResolvers; DepositFeesInformation?: DepositFeesInformationResolvers; DisplayCurrency?: GraphQLScalarType; Email?: EmailResolvers; @@ -5011,6 +5052,7 @@ export type Resolvers = { Merchant?: MerchantResolvers; MerchantPayload?: MerchantPayloadResolvers; Minutes?: GraphQLScalarType; + MobileSession?: MobileSessionResolvers; MobileVersions?: MobileVersionsResolvers; Mutation?: MutationResolvers; MyUpdatesPayload?: MyUpdatesPayloadResolvers; diff --git a/apps/map/services/galoy/graphql/generated.ts b/apps/map/services/galoy/graphql/generated.ts index 383fc968a0..0dce789e6d 100644 --- a/apps/map/services/galoy/graphql/generated.ts +++ b/apps/map/services/galoy/graphql/generated.ts @@ -449,6 +449,14 @@ export type CurrencyConversionEstimation = { readonly usdCentAmount: Scalars['CentAmount']['output']; }; +export type Delegation = { + readonly __typename: 'Delegation'; + readonly app: Scalars['String']['output']; + readonly handledAt: Scalars['Timestamp']['output']; + readonly remember: Scalars['Boolean']['output']; + readonly scope: ReadonlyArray; +}; + export type DepositFeesInformation = { readonly __typename: 'DepositFeesInformation'; readonly minBankFee: Scalars['String']['output']; @@ -877,6 +885,13 @@ export type MerchantPayload = { readonly merchant?: Maybe; }; +export type MobileSession = { + readonly __typename: 'MobileSession'; + readonly expiresAt: Scalars['Timestamp']['output']; + readonly id: Scalars['ID']['output']; + readonly issuedAt: Scalars['Timestamp']['output']; +}; + export type MobileVersions = { readonly __typename: 'MobileVersions'; readonly currentSupported: Scalars['Int']['output']; @@ -1914,6 +1929,8 @@ export type User = { readonly contacts: ReadonlyArray; readonly createdAt: Scalars['Timestamp']['output']; readonly defaultAccount: Account; + /** List of Oauth2 delegations */ + readonly delegations: ReadonlyArray; /** Email address */ readonly email?: Maybe; readonly id: Scalars['ID']['output']; @@ -1922,6 +1939,8 @@ export type User = { * When value is 'default' the intent is to use preferred language from OS settings. */ readonly language: Scalars['Language']['output']; + /** List of mobile sessions */ + readonly mobileSessions: ReadonlyArray; /** Phone number with international calling code. */ readonly phone?: Maybe; readonly supportChat: ReadonlyArray; diff --git a/apps/pay/lib/graphql/generated.ts b/apps/pay/lib/graphql/generated.ts index 68a092c98d..a114aef2d8 100644 --- a/apps/pay/lib/graphql/generated.ts +++ b/apps/pay/lib/graphql/generated.ts @@ -448,6 +448,14 @@ export type CurrencyConversionEstimation = { readonly usdCentAmount: Scalars['CentAmount']; }; +export type Delegation = { + readonly __typename: 'Delegation'; + readonly app: Scalars['String']; + readonly handledAt: Scalars['Timestamp']; + readonly remember: Scalars['Boolean']; + readonly scope: ReadonlyArray; +}; + export type DepositFeesInformation = { readonly __typename: 'DepositFeesInformation'; readonly minBankFee: Scalars['String']; @@ -876,6 +884,13 @@ export type MerchantPayload = { readonly merchant?: Maybe; }; +export type MobileSession = { + readonly __typename: 'MobileSession'; + readonly expiresAt: Scalars['Timestamp']; + readonly id: Scalars['ID']; + readonly issuedAt: Scalars['Timestamp']; +}; + export type MobileVersions = { readonly __typename: 'MobileVersions'; readonly currentSupported: Scalars['Int']; @@ -1913,6 +1928,8 @@ export type User = { readonly contacts: ReadonlyArray; readonly createdAt: Scalars['Timestamp']; readonly defaultAccount: Account; + /** List of Oauth2 delegations */ + readonly delegations: ReadonlyArray; /** Email address */ readonly email?: Maybe; readonly id: Scalars['ID']; @@ -1921,6 +1938,8 @@ export type User = { * When value is 'default' the intent is to use preferred language from OS settings. */ readonly language: Scalars['Language']; + /** List of mobile sessions */ + readonly mobileSessions: ReadonlyArray; /** Phone number with international calling code. */ readonly phone?: Maybe; readonly supportChat: ReadonlyArray; diff --git a/apps/voucher/cypress/e2e/consent-integration.cy.ts b/apps/voucher/cypress/e2e/consent-integration.cy.ts index 1f16fb1b18..08e9d9b023 100644 --- a/apps/voucher/cypress/e2e/consent-integration.cy.ts +++ b/apps/voucher/cypress/e2e/consent-integration.cy.ts @@ -32,22 +32,6 @@ describe("Consent integration Test", () => { cy.get("[data-testid=verification_code_input]").should("not.be.disabled") cy.get("[data-testid=verification_code_input]").type(code) - cy.contains("label", "read").should("exist") - cy.contains("label", "read").should("be.visible") - cy.contains("label", "read").should("not.be.disabled") - cy.contains("label", "read").should("not.be.disabled") - cy.contains("label", "read").click() - - cy.contains("label", "write").should("exist") - cy.contains("label", "write").should("be.visible") - cy.contains("label", "write").should("not.be.disabled") - cy.contains("label", "write").click() - - cy.get("[data-testid=submit_consent_btn]").should("exist") - cy.get("[data-testid=submit_consent_btn]").should("be.visible") - cy.get("[data-testid=submit_consent_btn]").should("not.be.disabled") - cy.get("[data-testid=submit_consent_btn]").click() - cy.url().should("eq", Cypress.config().baseUrl + "/") cy.getCookie("next-auth.session-token").then((cookie) => { if (cookie && cookie.value) { diff --git a/bats/core/api/user.bats b/bats/core/api/user.bats index 54e427cada..c16d74ab9b 100644 --- a/bats/core/api/user.bats +++ b/bats/core/api/user.bats @@ -24,3 +24,10 @@ setup_file() { language="$(graphql_output '.data.me.language')" [[ "$language" == "$new_language" ]] || exit 1 } + +@test "user: list sessions" { + exec_graphql 'alice' 'list-sessions' + sessions="$(graphql_output '.data.me.mobileSessions')" + id="$(echo "$sessions" | jq -r '.[0].id')" # Extracts the ID of the first element + [[ "$sessions" != "[]" ]] && [[ -n "$id" ]] || exit 1 +} diff --git a/bats/gql/list-sessions.gql b/bats/gql/list-sessions.gql new file mode 100644 index 0000000000..5a5ee558a6 --- /dev/null +++ b/bats/gql/list-sessions.gql @@ -0,0 +1,17 @@ +query userDetails { + me { + id + phone + mobileSessions { + id + expiresAt + issuedAt + } + delegations { + app + handledAt + remember + scope + } + } +} diff --git a/bats/helpers/user.bash b/bats/helpers/user.bash index d4800a9d5c..14b26073ca 100644 --- a/bats/helpers/user.bash +++ b/bats/helpers/user.bash @@ -75,9 +75,20 @@ create_user_with_metadata() { } random_phone() { - printf "+1%010d\n" $(( ($RANDOM * 1000000) + ($RANDOM % 1000000) )) + # Generate an area code: cannot start with 0 or 1 + local area_code=415 + + # Generate an exchange code: cannot start with 0 or 1 + local exchange=$(( $RANDOM % 800 + 200 )) + + # Generate a subscriber number: four-digit number + local subscriber=$(( $RANDOM % 10000 )) + + # Print formatted phone number + printf "+1%03d%03d%04d\n" $area_code $exchange $subscriber } + user_update_username() { local token_name="$1" diff --git a/core/api/package.json b/core/api/package.json index 9bcbb5ca03..114a49ee5e 100644 --- a/core/api/package.json +++ b/core/api/package.json @@ -182,6 +182,7 @@ "pino-pretty": "^10.3.1", "prettier": "^3.2.5", "protoc-gen-js": "^3.21.2", + "puppeteer": "^22.7.1", "react": "^18.2.0", "spectaql": "^2.3.1", "tiny-secp256k1": "^2.2.3", diff --git a/core/api/src/app/users/index.ts b/core/api/src/app/users/index.ts index 3748c982fb..e742c12ab0 100644 --- a/core/api/src/app/users/index.ts +++ b/core/api/src/app/users/index.ts @@ -3,6 +3,7 @@ import { UsersRepository } from "@/services/mongoose" export * from "./update-language" export * from "./get-user-language" export * from "./add-device-token" +export * from "./list-sessions" const users = UsersRepository() diff --git a/core/api/src/app/users/list-sessions.ts b/core/api/src/app/users/list-sessions.ts new file mode 100644 index 0000000000..ce51412502 --- /dev/null +++ b/core/api/src/app/users/list-sessions.ts @@ -0,0 +1,10 @@ +import { consentList } from "@/services/hydra" +import { listSessions as listSessionsService } from "@/services/kratos" + +export const listMobileSessions = async ({ userId }: { userId: UserId }) => { + return listSessionsService(userId) +} + +export const listDeleguations = async ({ userId }: { userId: UserId }) => { + return consentList(userId) +} diff --git a/core/api/src/domain/authentication/index.types.d.ts b/core/api/src/domain/authentication/index.types.d.ts index 4c553d297b..d8a9840931 100644 --- a/core/api/src/domain/authentication/index.types.d.ts +++ b/core/api/src/domain/authentication/index.types.d.ts @@ -61,10 +61,18 @@ type AnyIdentity = | IdentityPhoneEmail | IdentityDeviceAccount -type Session = { +type MobileSession = { identity: AnyIdentity id: SessionId expiresAt: Date + issuedAt: Date +} + +type Delegation = { + scope: string[] + handledAt: Date + remember: boolean + app: string } type WithSessionResponse = { diff --git a/core/api/src/graphql/public/schema.graphql b/core/api/src/graphql/public/schema.graphql index 2270e381ef..c8b6dd7e01 100644 --- a/core/api/src/graphql/public/schema.graphql +++ b/core/api/src/graphql/public/schema.graphql @@ -354,6 +354,13 @@ type CurrencyConversionEstimation { usdCentAmount: CentAmount! } +type Delegation { + app: String! + handledAt: Timestamp! + remember: Boolean! + scope: [String!]! +} + type DepositFeesInformation { minBankFee: String! @@ -865,6 +872,12 @@ type MerchantPayload { """(Positive) amount of minutes""" scalar Minutes +type MobileSession { + expiresAt: Timestamp! + id: ID! + issuedAt: Timestamp! +} + type MobileVersions { currentSupported: Int! minSupported: Int! @@ -1589,6 +1602,9 @@ type User { createdAt: Timestamp! defaultAccount: Account! + """List of Oauth2 delegations""" + delegations: [Delegation!]! + """Email address""" email: Email id: ID! @@ -1599,6 +1615,9 @@ type User { """ language: Language! + """List of mobile sessions""" + mobileSessions: [MobileSession!]! + """Phone number with international calling code.""" phone: Phone supportChat: [SupportMessage!]! diff --git a/core/api/src/graphql/public/types/object/deleguation.ts b/core/api/src/graphql/public/types/object/deleguation.ts new file mode 100644 index 0000000000..2e714efe63 --- /dev/null +++ b/core/api/src/graphql/public/types/object/deleguation.ts @@ -0,0 +1,15 @@ +import Timestamp from "@/graphql/shared/types/scalar/timestamp" + +import { GT } from "@/graphql/index" + +const Delegation = GT.Object({ + name: "Delegation", + fields: () => ({ + app: { type: GT.NonNull(GT.String) }, + handledAt: { type: GT.NonNull(Timestamp) }, + remember: { type: GT.NonNull(GT.Boolean) }, + scope: { type: GT.NonNullList(GT.String) }, + }), +}) + +export default Delegation diff --git a/core/api/src/graphql/public/types/object/mobile-session.ts b/core/api/src/graphql/public/types/object/mobile-session.ts new file mode 100644 index 0000000000..4368a04c6f --- /dev/null +++ b/core/api/src/graphql/public/types/object/mobile-session.ts @@ -0,0 +1,14 @@ +import Timestamp from "@/graphql/shared/types/scalar/timestamp" + +import { GT } from "@/graphql/index" + +const MobileSession = GT.Object({ + name: "MobileSession", + fields: () => ({ + id: { type: GT.NonNullID }, + issuedAt: { type: GT.NonNull(Timestamp) }, + expiresAt: { type: GT.NonNull(Timestamp) }, + }), +}) + +export default MobileSession diff --git a/core/api/src/graphql/public/types/object/user.ts b/core/api/src/graphql/public/types/object/user.ts index a55c425130..2a21c579df 100644 --- a/core/api/src/graphql/public/types/object/user.ts +++ b/core/api/src/graphql/public/types/object/user.ts @@ -4,6 +4,7 @@ import Account from "../abstract/account" import SupportMessage from "./support-message" import AccountContact from "./account-contact" +import Delegation from "./deleguation" import { Accounts, Users, SupportChat } from "@/app" @@ -19,6 +20,7 @@ import Language from "@/graphql/shared/types/scalar/language" import Username from "@/graphql/shared/types/scalar/username" import Timestamp from "@/graphql/shared/types/scalar/timestamp" import GraphQLEmail from "@/graphql/shared/types/object/email" +import MobileSession from "@/graphql/public/types/object/mobile-session" const GraphQLUser = GT.Object({ name: "User", @@ -75,6 +77,22 @@ const GraphQLUser = GT.Object({ }, }, + mobileSessions: { + type: GT.NonNullList(MobileSession), + description: "List of mobile sessions", + resolve: async (source, args, { user }) => { + return Users.listMobileSessions({ userId: user.id }) + }, + }, + + delegations: { + type: GT.NonNullList(Delegation), + description: "List of Oauth2 delegations", + resolve: async (source, args, { user }) => { + return Users.listDeleguations({ userId: user.id }) + }, + }, + contacts: { deprecationReason: "will be moved to account", type: GT.NonNullList(AccountContact), // TODO: Make it a Connection Interface diff --git a/core/api/src/services/hydra/index.ts b/core/api/src/services/hydra/index.ts new file mode 100644 index 0000000000..3e08646bf7 --- /dev/null +++ b/core/api/src/services/hydra/index.ts @@ -0,0 +1,38 @@ +import axios, { AxiosResponse } from "axios" + +const hydraUrl = process.env.HYDRA_ADMIN_URL || "http://localhost:4445" + +export const consentList = async (userId: UserId): Promise => { + /* eslint @typescript-eslint/ban-ts-comment: "off" */ + // @ts-ignore-next-line no-implicit-any error + let res: AxiosResponse + + try { + res = await axios.get( + `${hydraUrl}/admin/oauth2/auth/sessions/consent?subject=${userId}`, + ) + } catch (err) { + // TODO + console.error(err) + return [] + } + + let sessions: Delegation[] + + try { + /* eslint @typescript-eslint/ban-ts-comment: "off" */ + // @ts-ignore-next-line no-implicit-any error + sessions = res.data.map((request) => ({ + scope: request.grant_scope, + handledAt: new Date(request.handled_at), + remember: request.remember, + app: request.consent_request.client.client_name, + })) + } catch (err) { + // TODO + console.error(err) + return [] + } + + return sessions +} diff --git a/core/api/src/services/kratos/index.ts b/core/api/src/services/kratos/index.ts index 33abee3733..5fba743ff4 100644 --- a/core/api/src/services/kratos/index.ts +++ b/core/api/src/services/kratos/index.ts @@ -61,7 +61,7 @@ export const checkedToAuthToken = (value: string) => { export const validateKratosToken = async ( authToken: AuthToken, ): Promise => { - let session: Session + let session: MobileSession try { const { data } = await kratosPublic.toSession({ xSessionToken: authToken }) @@ -80,7 +80,9 @@ export const validateKratosToken = async ( } } -export const listSessions = async (userId: UserId): Promise => { +export const listSessions = async ( + userId: UserId, +): Promise => { try { const res = await kratosAdmin.listIdentitySessions({ id: userId }) if (res.data === null) return [] diff --git a/core/api/src/services/kratos/index.types.d.ts b/core/api/src/services/kratos/index.types.d.ts index cb59e9f9da..69d0715d57 100644 --- a/core/api/src/services/kratos/index.types.d.ts +++ b/core/api/src/services/kratos/index.types.d.ts @@ -14,7 +14,7 @@ type IdentitySchemaContainer = import("@ory/client").IdentitySchemaContainer type ValidateKratosTokenResult = { kratosUserId: UserId - session: Session + session: MobileSession } type KratosPublicMetadata = { diff --git a/core/api/src/services/kratos/private.ts b/core/api/src/services/kratos/private.ts index bf7abad862..a9f1b243c3 100644 --- a/core/api/src/services/kratos/private.ts +++ b/core/api/src/services/kratos/private.ts @@ -1,13 +1,8 @@ import knex from "knex" -import { Configuration, FrontendApi, IdentityApi } from "@ory/client" +import { Configuration, FrontendApi, Identity, IdentityApi } from "@ory/client" -import { - InvalidIdentitySessionKratosError, - MissingCreatedAtKratosError, - MissingExpiredAtKratosError, - UnknownKratosError, -} from "./errors" +import { MissingCreatedAtKratosError, UnknownKratosError } from "./errors" import { SchemaIdType } from "./schema" @@ -30,16 +25,12 @@ export const getKratosPostgres = () => connection: KRATOS_PG_CON, }) -export const toDomainSession = (session: KratosSession): Session => { - // is throw ok? this should not happen I (nb) believe but the type say it can - // this may probably be a type issue in kratos SDK - if (!session.identity) throw new InvalidIdentitySessionKratosError() - if (!session.expires_at) throw new MissingExpiredAtKratosError() - +export const toDomainSession = (session: KratosSession): MobileSession => { return { id: session.id as SessionId, - identity: toDomainIdentity(session.identity), - expiresAt: new Date(session?.expires_at), + identity: toDomainIdentity(session.identity as Identity), + expiresAt: new Date(session?.expires_at as string), + issuedAt: new Date(session?.issued_at as string), } } diff --git a/core/api/test/integration/app/user/consent-list.spec.ts b/core/api/test/integration/app/user/consent-list.spec.ts new file mode 100644 index 0000000000..db5b986f1f --- /dev/null +++ b/core/api/test/integration/app/user/consent-list.spec.ts @@ -0,0 +1,107 @@ +import puppeteer from "puppeteer" + +import { Admin } from "@/app" +import { consentList } from "@/services/hydra" +import { sleep } from "@/utils" +import knex from "knex" + +let userId: UserId +const email = "test@galoy.io" as EmailAddress + +beforeAll(async () => { + const account = await Admin.getAccountByUserEmail(email) + if (account instanceof Error) throw account + + userId = account.kratosUserId +}) + +const db = knex({ + client: "pg", + connection: "postgres://dbuser:secret@localhost:5432/default?sslmode=disable", +}) + +const getOTP = (email: string): Promise => { + return db<{ body: string }>("courier_messages") // Specifying the expected row structure + .select("body") + .where("recipient", email) + .orderBy("created_at", "desc") + .limit(1) + .then((rows) => { + if (rows.length === 0) { + throw new Error("OTP not found in the message") + } + const otpMatch = rows[0].body.match(/(\d{6})/) + if (otpMatch && otpMatch[1]) { + return otpMatch[1] + } else { + throw new Error("OTP not found in the message") + } + }) + .catch((error) => { + throw new Error(`Error retrieving OTP: ${error.message}`) + }) +} + +async function performOAuthLogin() { + const screenshots = false + + const browser = await puppeteer.launch() + // const browser = await puppeteer.launch({ headless: true }) + const page = await browser.newPage() + + // Navigate the page to a URL + await page.goto("http://localhost:3001/api/auth/signin") + + screenshots && (await page.screenshot({ path: "screenshot0.png" })) + + await page.waitForSelector(".button") + await page.click(".button") + + screenshots && (await page.screenshot({ path: "screenshot1.png" })) + + await page.waitForSelector('[data-testid="email_id_input"]') + await page.waitForFunction( + "document.querySelector(\"[data-testid='email_id_input']\").isConnected", + ) + await page.type('[data-testid="email_id_input"]', email) + screenshots && (await page.screenshot({ path: "screenshot2.png" })) + await sleep(1000) + + await page.click("#accept") + + await sleep(1000) + screenshots && (await page.screenshot({ path: "screenshot3.png" })) + + const otp = await getOTP(email) + + await page.waitForSelector("#code") + await page.type("#code", otp) + + screenshots && (await page.screenshot({ path: "screenshot4.png" })) + await sleep(1500) + screenshots && (await page.screenshot({ path: "screenshot5.png" })) + + await page.close() + await browser.close() +} + +describe("Hydra", () => { + it("get an empty consent list", async () => { + const res = await consentList(userId) + expect(res).toEqual([]) + }) + + it("get consent list when the user had perform oauth2 login", async () => { + await performOAuthLogin() + + const res = await consentList(userId) + expect(res).toEqual([ + { + app: "dashboard", + handledAt: expect.any(Date), + remember: false, + scope: ["read", "write"], + }, + ]) + }) +}) diff --git a/dev/bin/setup-hydra-client.sh b/dev/bin/setup-hydra-client.sh index c650c6bd9f..ecf77ffa24 100755 --- a/dev/bin/setup-hydra-client.sh +++ b/dev/bin/setup-hydra-client.sh @@ -21,7 +21,8 @@ hydra_cli create client \ --format json \ --scope read --scope write \ --redirect-uri "$redirect_uri" > "${HYDRA_CLIENT_JSON}" \ - --name "${hydra_client_name}" + --name "${hydra_client_name}" \ + --skip-consent CLIENT_ID=$(jq -r '.client_id' < "${HYDRA_CLIENT_JSON}") CLIENT_SECRET=$(jq -r '.client_secret' < "${HYDRA_CLIENT_JSON}") diff --git a/dev/config/apollo-federation/supergraph.graphql b/dev/config/apollo-federation/supergraph.graphql index 8a31227676..e9db449eeb 100644 --- a/dev/config/apollo-federation/supergraph.graphql +++ b/dev/config/apollo-federation/supergraph.graphql @@ -486,6 +486,15 @@ type CurrencyConversionEstimation usdCentAmount: CentAmount! } +type Delegation + @join__type(graph: PUBLIC) +{ + app: String! + handledAt: Timestamp! + remember: Boolean! + scope: [String!]! +} + type DepositFeesInformation @join__type(graph: PUBLIC) { @@ -1142,6 +1151,14 @@ type MerchantPayload scalar Minutes @join__type(graph: PUBLIC) +type MobileSession + @join__type(graph: PUBLIC) +{ + expiresAt: Timestamp! + id: ID! + issuedAt: Timestamp! +} + type MobileVersions @join__type(graph: PUBLIC) { @@ -2077,6 +2094,9 @@ type User createdAt: Timestamp! @join__field(graph: PUBLIC) defaultAccount: Account! @join__field(graph: PUBLIC) + """List of Oauth2 delegations""" + delegations: [Delegation!]! @join__field(graph: PUBLIC) + """Email address""" email: Email @join__field(graph: PUBLIC) @@ -2086,6 +2106,9 @@ type User """ language: Language! @join__field(graph: PUBLIC) + """List of mobile sessions""" + mobileSessions: [MobileSession!]! @join__field(graph: PUBLIC) + """Phone number with international calling code.""" phone: Phone @join__field(graph: PUBLIC) supportChat: [SupportMessage!]! @join__field(graph: PUBLIC) diff --git a/docs/hydra.md b/docs/hydra.md index f0657fc4bc..e2ba42b179 100644 --- a/docs/hydra.md +++ b/docs/hydra.md @@ -10,27 +10,15 @@ Make sure you have `hydra` command line installed brew install ory-hydra ``` -# run the experiment: +### list oauth2 client generated from tilt -Follow the instructions below +hydra list oauth2-clients -e http://localhost:4445 +## loading env from automatically created client: -On console 1: - -launch the hydra login consent node, which will provide the authentication (interactive with kratos API) and consent page. - -```sh -apps/consent % HYDRA_ADMIN_URL=http://localhost:4445 yarn start -``` - -On console 2: -```sh -galoy % make start -``` - -On console 3: -Follow the instructions below +. ./dev/.dashboard-hydra-client.env +TODO: dashboard should have consent: true automatically ## create a OAuth2 client @@ -41,8 +29,8 @@ The client is concourse in this example. For the galoy stack, some examples of clients could be Alby, a boltcard service, a nostr wallet connect service, an accountant that access the wallet in read only. - from :dashboard + ```sh . ./.env @@ -84,7 +72,6 @@ pnpm next note: skip consent should be true for trust client, ie: dashboard, but not for third party clients - to do a PKCE session: ```sh @@ -132,7 +119,6 @@ hydra introspect token \ OR - ```sh curl -X POST http://localhost:4445/admin/oauth2/introspect -d token=$ory_at_TOKEN @@ -177,7 +163,6 @@ but the response is not returning the scope in the jwt curl -s -I -X POST http://localhost:4456/decisions/graphql --user $client_id:$client_secret ``` - ## list OAuth 2.0 consent ```sh @@ -185,14 +170,13 @@ export subject="9818ea5e-30a8-4b52-879d-d34590e7250e" curl "http://localhost:4445/admin/oauth2/auth/sessions/consent?subject=$subject" ``` -login_session_id (optional): The login session id to list the consent sessions for. +login_session_id (optional): The login session id to list the consent sessions for. ## change client token lifespans https://www.ory.sh/docs/reference/api#tag/oAuth2/operation/setOAuth2ClientLifespans - ## delete token by session id export session_id="b3fc4e84-4f73-4229-acdd-9bbaba00ca60" @@ -201,10 +185,8 @@ curl -v -X DELETE "http://localhost:4445/admin/oauth2/auth/sessions/login?sid=$s export subject=9818ea5e-30a8-4b52-879d-d34590e7250e curl -v -X DELETE "http://localhost:4445/admin/oauth2/auth/sessions/login?subject=$subject" - # delete all -curl -v -X DELETE "http://localhost:4445/admin/oauth2/auth/sessions/consent?subject=$subject&client=$CLIENT_ID_APP_API_KEY" - +curl -v -X DELETE "http://localhost:4445/admin/oauth2/auth/sessions/consent?subject=$subject&client=$CLIENT_ID_APP_API_KEY" curl http://localhost:4445/admin/oauth2/auth/requests/logout diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ac7ee703f1..7b801faf58 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1471,6 +1471,9 @@ importers: protoc-gen-js: specifier: ^3.21.2 version: 3.21.2 + puppeteer: + specifier: ^22.7.1 + version: 22.7.1(typescript@5.4.5) react: specifier: ^18.2.0 version: 18.2.0 @@ -2895,7 +2898,7 @@ packages: '@babel/traverse': 7.24.0 '@babel/types': 7.24.0 convert-source-map: 1.9.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -2918,7 +2921,7 @@ packages: '@babel/traverse': 7.23.5 '@babel/types': 7.23.5 convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -2941,7 +2944,7 @@ packages: '@babel/traverse': 7.24.0 '@babel/types': 7.24.0 convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -3161,7 +3164,7 @@ packages: '@babel/core': 7.23.5 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-plugin-utils': 7.24.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -3176,7 +3179,7 @@ packages: '@babel/core': 7.24.4 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-plugin-utils': 7.24.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -3191,7 +3194,7 @@ packages: '@babel/core': 7.24.0 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-plugin-utils': 7.24.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -3206,7 +3209,7 @@ packages: '@babel/core': 7.24.4 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-plugin-utils': 7.24.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -6938,7 +6941,7 @@ packages: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.24.0 '@babel/types': 7.24.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -6956,7 +6959,7 @@ packages: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.24.4 '@babel/types': 7.24.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -7711,7 +7714,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.1 @@ -9763,7 +9766,7 @@ packages: '@types/json-stable-stringify': 1.0.34 '@whatwg-node/fetch': 0.8.8 chalk: 4.1.2 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) dotenv: 16.4.5 graphql: 16.8.1 graphql-request: 6.1.0(graphql@16.8.1) @@ -9796,7 +9799,7 @@ packages: '@types/json-stable-stringify': 1.0.36 '@whatwg-node/fetch': 0.9.17 chalk: 4.1.2 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) dotenv: 16.4.5 graphql: 16.8.1 graphql-request: 6.1.0(graphql@16.8.1) @@ -9829,7 +9832,7 @@ packages: '@types/json-stable-stringify': 1.0.36 '@whatwg-node/fetch': 0.9.17 chalk: 4.1.2 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) dotenv: 16.4.5 graphql: 16.8.1 graphql-request: 6.1.0(graphql@16.8.1) @@ -10221,7 +10224,7 @@ packages: engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 2.0.1 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -10296,6 +10299,49 @@ packages: slash: 3.0.0 dev: true + /@jest/core@29.7.0: + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.12.7 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.12.7) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.5 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + dev: true + /@jest/core@29.7.0(ts-node@10.9.2): resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -12276,6 +12322,23 @@ packages: resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} dev: false + /@puppeteer/browsers@2.2.3: + resolution: {integrity: sha512-bJ0UBsk0ESOs6RFcLXOt99a3yTDcOKlzfjad+rhFwdaG1Lu/Wzq58GHYCDTlZ9z6mldf4g+NTb+TXEfe0PpnsQ==} + engines: {node: '>=18'} + hasBin: true + dependencies: + debug: 4.3.4(supports-color@5.5.0) + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.4.0 + semver: 7.6.0 + tar-fs: 3.0.5 + unbzip2-stream: 1.4.3 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + dev: true + /@radix-ui/number@1.0.1: resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} dependencies: @@ -15133,7 +15196,7 @@ packages: typescript: '>= 4.x' webpack: '>= 4' dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) endent: 2.1.0 find-cache-dir: 3.3.2 flat-cache: 3.2.0 @@ -15961,6 +16024,10 @@ packages: engines: {node: '>= 10'} requiresBuild: true + /@tootallnate/quickjs-emscripten@0.23.0: + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + dev: true + /@trysound/sax@0.2.0: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} @@ -16795,7 +16862,7 @@ packages: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/type-utils': 5.62.0(eslint@8.54.0)(typescript@5.2.2) '@typescript-eslint/utils': 5.62.0(eslint@8.54.0)(typescript@5.2.2) - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.54.0 graphemer: 1.4.0 ignore: 5.3.0 @@ -16823,7 +16890,7 @@ packages: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/type-utils': 5.62.0(eslint@8.54.0)(typescript@5.2.2) '@typescript-eslint/utils': 5.62.0(eslint@8.54.0)(typescript@5.2.2) - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.54.0 graphemer: 1.4.0 ignore: 5.3.0 @@ -16852,7 +16919,7 @@ packages: '@typescript-eslint/type-utils': 7.1.1(eslint@8.57.0)(typescript@5.3.3) '@typescript-eslint/utils': 7.1.1(eslint@8.57.0)(typescript@5.3.3) '@typescript-eslint/visitor-keys': 7.1.1 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 @@ -16881,7 +16948,7 @@ packages: '@typescript-eslint/type-utils': 7.1.1(eslint@8.57.0)(typescript@5.2.2) '@typescript-eslint/utils': 7.1.1(eslint@8.57.0)(typescript@5.2.2) '@typescript-eslint/visitor-keys': 7.1.1 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 @@ -16948,7 +17015,7 @@ packages: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5) - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.40.0 typescript: 5.4.5 transitivePeerDependencies: @@ -16968,7 +17035,7 @@ packages: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.2.2) - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.54.0 typescript: 5.2.2 transitivePeerDependencies: @@ -16989,7 +17056,7 @@ packages: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.2.2) '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.54.0 typescript: 5.2.2 transitivePeerDependencies: @@ -17010,7 +17077,7 @@ packages: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.2.2) '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 typescript: 5.2.2 transitivePeerDependencies: @@ -17031,7 +17098,7 @@ packages: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3) '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 typescript: 5.3.3 transitivePeerDependencies: @@ -17052,7 +17119,7 @@ packages: '@typescript-eslint/types': 7.0.2 '@typescript-eslint/typescript-estree': 7.0.2(typescript@5.2.2) '@typescript-eslint/visitor-keys': 7.0.2 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.54.0 typescript: 5.2.2 transitivePeerDependencies: @@ -17073,7 +17140,7 @@ packages: '@typescript-eslint/types': 7.1.1 '@typescript-eslint/typescript-estree': 7.1.1(typescript@5.3.3) '@typescript-eslint/visitor-keys': 7.1.1 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 typescript: 5.3.3 transitivePeerDependencies: @@ -17115,7 +17182,7 @@ packages: '@typescript-eslint/types': 7.7.1 '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.2.2) '@typescript-eslint/visitor-keys': 7.7.1 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 typescript: 5.2.2 transitivePeerDependencies: @@ -17181,7 +17248,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.2.2) '@typescript-eslint/utils': 5.62.0(eslint@8.54.0)(typescript@5.2.2) - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.54.0 tsutils: 3.21.0(typescript@5.2.2) typescript: 5.2.2 @@ -17201,7 +17268,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 7.1.1(typescript@5.2.2) '@typescript-eslint/utils': 7.1.1(eslint@8.57.0)(typescript@5.2.2) - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 ts-api-utils: 1.2.1(typescript@5.2.2) typescript: 5.2.2 @@ -17221,7 +17288,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 7.1.1(typescript@5.3.3) '@typescript-eslint/utils': 7.1.1(eslint@8.57.0)(typescript@5.3.3) - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 ts-api-utils: 1.2.1(typescript@5.3.3) typescript: 5.3.3 @@ -17336,7 +17403,7 @@ packages: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.0 @@ -17357,7 +17424,7 @@ packages: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.0 @@ -17378,7 +17445,7 @@ packages: dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -17400,7 +17467,7 @@ packages: dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -17444,7 +17511,7 @@ packages: dependencies: '@typescript-eslint/types': 7.0.2 '@typescript-eslint/visitor-keys': 7.0.2 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -17466,7 +17533,7 @@ packages: dependencies: '@typescript-eslint/types': 7.1.1 '@typescript-eslint/visitor-keys': 7.1.1 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -17488,7 +17555,7 @@ packages: dependencies: '@typescript-eslint/types': 7.1.1 '@typescript-eslint/visitor-keys': 7.1.1 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -17532,7 +17599,7 @@ packages: dependencies: '@typescript-eslint/types': 7.7.1 '@typescript-eslint/visitor-keys': 7.7.1 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 @@ -18270,6 +18337,15 @@ packages: transitivePeerDependencies: - supports-color + /agent-base@7.1.1: + resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} + engines: {node: '>= 14'} + dependencies: + debug: 4.3.4(supports-color@5.5.0) + transitivePeerDependencies: + - supports-color + dev: true + /agentkeepalive@4.5.0: resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} engines: {node: '>= 8.0.0'} @@ -18655,6 +18731,13 @@ packages: /ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + /ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + dependencies: + tslib: 2.6.2 + dev: true + /ast-types@0.16.1: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} @@ -18835,7 +18918,6 @@ packages: /b4a@1.6.4: resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==} - dev: false /babel-core@7.0.0-bridge.0(@babel/core@7.24.4): resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} @@ -19163,6 +19245,44 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + /bare-events@2.2.2: + resolution: {integrity: sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==} + requiresBuild: true + dev: true + optional: true + + /bare-fs@2.3.0: + resolution: {integrity: sha512-TNFqa1B4N99pds2a5NYHR15o0ZpdNKbAeKTE/+G6ED/UeOavv8RY3dr/Fu99HW3zU3pXpo2kDNO8Sjsm2esfOw==} + requiresBuild: true + dependencies: + bare-events: 2.2.2 + bare-path: 2.1.2 + bare-stream: 1.0.0 + dev: true + optional: true + + /bare-os@2.3.0: + resolution: {integrity: sha512-oPb8oMM1xZbhRQBngTgpcQ5gXw6kjOaRsSWsIeNyRxGed2w/ARyP7ScBYpWR1qfX2E5rS3gBw6OWcSQo+s+kUg==} + requiresBuild: true + dev: true + optional: true + + /bare-path@2.1.2: + resolution: {integrity: sha512-o7KSt4prEphWUHa3QUwCxUI00R86VdjiuxmJK0iNVDHYPGo+HsDaVCnqCmPbf/MiW1ok8F4p3m8RTHlWk8K2ig==} + requiresBuild: true + dependencies: + bare-os: 2.3.0 + dev: true + optional: true + + /bare-stream@1.0.0: + resolution: {integrity: sha512-KhNUoDL40iP4gFaLSsoGE479t0jHijfYdIcxRn/XtezA2BaUD0NRf/JGRpsMq6dMNM+SrCrB0YSSo/5wBY4rOQ==} + requiresBuild: true + dependencies: + streamx: 2.16.1 + dev: true + optional: true + /base-x@3.0.9: resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} dependencies: @@ -19192,6 +19312,11 @@ packages: dependencies: safe-buffer: 5.1.2 + /basic-ftp@5.0.5: + resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} + engines: {node: '>=10.0.0'} + dev: true + /batch@0.6.1: resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} dev: true @@ -19910,7 +20035,7 @@ packages: '@testim/chrome-version': 1.1.4 axios: 1.6.8 compare-versions: 6.1.0 - extract-zip: 2.0.1 + extract-zip: 2.0.1(supports-color@8.1.1) https-proxy-agent: 5.0.1 proxy-from-env: 1.1.0 tcp-port-used: 1.0.2 @@ -19919,6 +20044,17 @@ packages: - supports-color dev: true + /chromium-bidi@0.5.19(devtools-protocol@0.0.1273771): + resolution: {integrity: sha512-UA6zL77b7RYCjJkZBsZ0wlvCTD+jTjllZ8f6wdO4buevXgTZYjV+XLB9CiEa2OuuTGGTLnI7eN9I60YxuALGQg==} + peerDependencies: + devtools-protocol: '*' + dependencies: + devtools-protocol: 0.0.1273771 + mitt: 3.0.1 + urlpattern-polyfill: 10.0.0 + zod: 3.22.4 + dev: true + /ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -20453,6 +20589,22 @@ packages: typescript: 5.4.5 dev: true + /cosmiconfig@9.0.0(typescript@5.4.5): + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + typescript: 5.4.5 + dev: true + /country-flag-icons@1.5.7: resolution: {integrity: sha512-AdvXhMcmSp7nBSkpGfW4qR/luAdRUutJqya9PuwRbsBzuoknThfultbv7Ib6fWsHXC43Es/4QJ8gzQQdBNm75A==} dev: false @@ -20497,6 +20649,25 @@ packages: - ts-node dev: true + /create-jest@29.7.0(@types/node@20.12.7): + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@20.12.7) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + /create-jest@29.7.0(@types/node@20.12.7)(ts-node@10.9.2): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -20856,6 +21027,11 @@ packages: assert-plus: 1.0.0 dev: true + /data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} + dev: true + /data-urls@3.0.2: resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} engines: {node: '>=12'} @@ -20904,6 +21080,16 @@ packages: dependencies: ms: 2.0.0 + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + /debug@3.2.7(supports-color@8.1.1): resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -20950,7 +21136,6 @@ packages: dependencies: ms: 2.1.2 supports-color: 8.1.1 - dev: true /decamelize@1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} @@ -21126,6 +21311,15 @@ packages: resolution: {integrity: sha512-Vy2wmG3NTkmHNg/kzpuvHhkqeIx3ODWqasgCRbKtbXEN0G+HpEEv9BtJLp7ZG1CZloFaC41Ah3ZFbq7aqCqMeQ==} dev: true + /degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + dev: true + /del@6.1.1: resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} engines: {node: '>=10'} @@ -21245,7 +21439,7 @@ packages: hasBin: true dependencies: address: 1.2.2 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: true @@ -21404,6 +21598,10 @@ packages: - supports-color dev: true + /devtools-protocol@0.0.1273771: + resolution: {integrity: sha512-QDbb27xcTVReQQW/GHJsdQqGKwYBE7re7gxehj467kKP2DKuYBUj6i2k5LRiAC66J1yZG/9gsxooz/s9pcm0Og==} + dev: true + /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} @@ -21719,6 +21917,11 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + /env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + dev: true + /envinfo@7.11.0: resolution: {integrity: sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==} engines: {node: '>=4'} @@ -21952,7 +22155,7 @@ packages: peerDependencies: esbuild: '>=0.12 <1' dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) esbuild: 0.18.20 transitivePeerDependencies: - supports-color @@ -22198,7 +22401,7 @@ packages: /eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7 is-core-module: 2.13.1 resolve: 1.22.8 transitivePeerDependencies: @@ -22211,7 +22414,7 @@ packages: eslint: '*' eslint-plugin-import: '*' dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) enhanced-resolve: 5.15.0 eslint: 8.40.0 eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.40.0) @@ -22234,7 +22437,7 @@ packages: eslint: '*' eslint-plugin-import: '*' dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) enhanced-resolve: 5.15.0 eslint: 8.54.0 eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0) @@ -22257,7 +22460,7 @@ packages: eslint: '*' eslint-plugin-import: '*' dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) enhanced-resolve: 5.15.0 eslint: 8.57.0 eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) @@ -22472,7 +22675,7 @@ packages: optional: true dependencies: '@typescript-eslint/parser': 7.7.0(eslint@8.57.0)(typescript@5.4.5) - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: @@ -22713,7 +22916,7 @@ packages: array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7 doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 @@ -23150,7 +23353,7 @@ packages: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -23200,7 +23403,7 @@ packages: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -23597,7 +23800,6 @@ packages: /fast-fifo@1.3.2: resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} - dev: false /fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} @@ -24404,6 +24606,18 @@ packages: dependencies: resolve-pkg-maps: 1.0.0 + /get-uri@6.0.3: + resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==} + engines: {node: '>= 14'} + dependencies: + basic-ftp: 5.0.5 + data-uri-to-buffer: 6.0.2 + debug: 4.3.4(supports-color@5.5.0) + fs-extra: 11.2.0 + transitivePeerDependencies: + - supports-color + dev: true + /getobject@1.0.2: resolution: {integrity: sha512-2zblDBaFcb3rB4rF77XVnuINOE2h2k/OnqXAiy0IrTxUfV1iFp3la33oAQVY9pCpWU268WFYVt2t71hlMuLsOg==} engines: {node: '>=10'} @@ -25505,7 +25719,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: true @@ -25572,7 +25786,7 @@ packages: engines: {node: '>= 6.0.0'} dependencies: agent-base: 5.1.1 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: true @@ -25591,7 +25805,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: true @@ -25861,7 +26075,6 @@ packages: dependencies: jsbn: 1.1.0 sprintf-js: 1.1.3 - dev: false /ip-regex@4.3.0: resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==} @@ -26478,14 +26691,14 @@ packages: node-notifier: optional: true dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2) + '@jest/core': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.12.7)(ts-node@10.9.2) + create-jest: 29.7.0(@types/node@20.12.7) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.12.7)(ts-node@10.9.2) + jest-config: 29.7.0(@types/node@20.12.7) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -26564,6 +26777,46 @@ packages: - supports-color dev: true + /jest-config@29.7.0(@types/node@20.12.7): + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.24.4 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.12.7 + babel-jest: 29.7.0(@babel/core@7.24.4) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + /jest-config@29.7.0(@types/node@20.12.7)(ts-node@10.9.2): resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -26961,7 +27214,7 @@ packages: node-notifier: optional: true dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2) + '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.1.0 jest-cli: 29.7.0(@types/node@20.12.7) @@ -27094,7 +27347,6 @@ packages: /jsbn@1.1.0: resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - dev: false /jscodeshift@0.15.1(@babel/preset-env@7.24.4): resolution: {integrity: sha512-hIJfxUy8Rt4HkJn/zZPU9ChKfKZM1342waJ1QC2e2YsPcWhM+3BJ4dcfQCzArTrk1jJeNLB341H+qOcEHRxJZg==} @@ -27697,7 +27949,7 @@ packages: bignumber.js: 9.1.2 bolt11: 1.4.1 commander: 12.0.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) express: 4.19.2 lightning-backends: 1.6.3 lnurl-offline: 1.2.0 @@ -27960,7 +28212,6 @@ packages: /lru-cache@7.18.3: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} - dev: false /lru-memoizer@2.2.0: resolution: {integrity: sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==} @@ -28397,6 +28648,10 @@ packages: yallist: 4.0.0 dev: true + /mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + dev: true + /mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} @@ -28651,6 +28906,11 @@ packages: /neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + /netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + dev: true + /next-auth@4.24.5(next@14.0.4)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-3RafV3XbfIKk6rF6GlLE4/KxjTcuMCifqrmD+98ejFq73SRoj2rmzoca8u764977lH/Q7jo6Xu6yM+Re1Mz/Og==} peerDependencies: @@ -29459,6 +29719,30 @@ packages: engines: {node: '>=6'} dev: true + /pac-proxy-agent@7.0.1: + resolution: {integrity: sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==} + engines: {node: '>= 14'} + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.0 + debug: 4.3.4(supports-color@5.5.0) + get-uri: 6.0.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.4 + pac-resolver: 7.0.1 + socks-proxy-agent: 8.0.3 + transitivePeerDependencies: + - supports-color + dev: true + + /pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} + dependencies: + degenerator: 5.0.1 + netmask: 2.0.2 + dev: true + /pako@0.2.9: resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} dev: true @@ -30466,6 +30750,22 @@ packages: forwarded: 0.2.0 ipaddr.js: 1.9.1 + /proxy-agent@6.4.0: + resolution: {integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4(supports-color@5.5.0) + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.4 + lru-cache: 7.18.3 + pac-proxy-agent: 7.0.1 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.3 + transitivePeerDependencies: + - supports-color + dev: true + /proxy-from-env@1.0.0: resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==} dev: true @@ -30536,7 +30836,7 @@ packages: engines: {node: '>=8.16.0'} dependencies: '@types/mime-types': 2.1.4 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) extract-zip: 1.7.0 https-proxy-agent: 4.0.0 mime: 2.6.0 @@ -30551,6 +30851,38 @@ packages: - utf-8-validate dev: true + /puppeteer-core@22.7.1: + resolution: {integrity: sha512-jD7T7yN7PWGuJmNT0TAEboA26s0VVnvbgCxqgQIF+eNQW2u71ENaV2JwzSJiCHO+e72H4Ue6AgKD9USQ8xAcOQ==} + engines: {node: '>=18'} + dependencies: + '@puppeteer/browsers': 2.2.3 + chromium-bidi: 0.5.19(devtools-protocol@0.0.1273771) + debug: 4.3.4(supports-color@5.5.0) + devtools-protocol: 0.0.1273771 + ws: 8.16.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + + /puppeteer@22.7.1(typescript@5.4.5): + resolution: {integrity: sha512-JBCBCwQ9+dyPp5haqeecgv0N0vgWFx44woUeKJaPeJT8CU3RXrd8F/tqJQbuAmcWlbMhYJSlTJkIFrwVAs6BNA==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true + dependencies: + '@puppeteer/browsers': 2.2.3 + cosmiconfig: 9.0.0(typescript@5.4.5) + devtools-protocol: 0.0.1273771 + puppeteer-core: 22.7.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - typescript + - utf-8-validate + dev: true + /pure-rand@6.0.4: resolution: {integrity: sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==} dev: true @@ -30629,7 +30961,6 @@ packages: /queue-tick@1.0.1: resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} - dev: false /quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} @@ -32056,7 +32387,6 @@ packages: /smart-buffer@4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - dev: false /snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} @@ -32069,19 +32399,29 @@ packages: engines: {node: '>= 10'} dependencies: agent-base: 6.0.2 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) socks: 2.8.3 transitivePeerDependencies: - supports-color dev: false + /socks-proxy-agent@8.0.3: + resolution: {integrity: sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.1 + debug: 4.3.4(supports-color@5.5.0) + socks: 2.8.3 + transitivePeerDependencies: + - supports-color + dev: true + /socks@2.8.3: resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} dependencies: ip-address: 9.0.5 smart-buffer: 4.2.0 - dev: false /sonic-boom@3.7.0: resolution: {integrity: sha512-IudtNvSqA/ObjN97tfgNmOKyDOs4dNcg4cUUsHDebqsgb8wGBBwb31LIgShNO8fye0dFI52X1+tFoKKI6Rq1Gg==} @@ -32392,7 +32732,17 @@ packages: dependencies: fast-fifo: 1.3.2 queue-tick: 1.0.1 - dev: false + + /streamx@2.16.1: + resolution: {integrity: sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==} + requiresBuild: true + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + optionalDependencies: + bare-events: 2.2.2 + dev: true + optional: true /strict-uri-encode@1.1.0: resolution: {integrity: sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==} @@ -32879,6 +33229,16 @@ packages: tar-stream: 3.1.7 dev: false + /tar-fs@3.0.5: + resolution: {integrity: sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==} + dependencies: + pump: 3.0.0 + tar-stream: 3.1.7 + optionalDependencies: + bare-fs: 2.3.0 + bare-path: 2.1.2 + dev: true + /tar-stream@1.6.2: resolution: {integrity: sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==} engines: {node: '>= 0.8.0'} @@ -32908,7 +33268,6 @@ packages: b4a: 1.6.4 fast-fifo: 1.3.2 streamx: 2.15.6 - dev: false /tar@6.2.0: resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==} @@ -33158,7 +33517,7 @@ packages: resolution: {integrity: sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==} dependencies: body: 5.1.0 - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7 faye-websocket: 0.10.0 livereload-js: 2.4.0 object-assign: 4.1.1 @@ -34941,7 +35300,6 @@ packages: /zod@3.22.4: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} - dev: false /zod@3.23.4: resolution: {integrity: sha512-/AtWOKbBgjzEYYQRNfoGKHObgfAZag6qUJX1VbHo2PRBgS+wfWagEY2mizjfyAPcGesrJOcx/wcl0L9WnVrHFw==}