diff --git a/packages/cellix/serenity-framework/src/clients/graphql-client.ts b/packages/cellix/serenity-framework/src/clients/graphql-client.ts index 7aaa5076f..1f1bae4c0 100644 --- a/packages/cellix/serenity-framework/src/clients/graphql-client.ts +++ b/packages/cellix/serenity-framework/src/clients/graphql-client.ts @@ -27,6 +27,12 @@ export interface GraphQLClientOptions { fetch?: typeof fetch; } +/** Per-request options for {@link GraphQLClient.execute}. */ +export interface GraphQLExecuteOptions { + /** Additional headers merged with default client headers for this request. */ + headers?: Record; +} + /** * Serenity ability for executing GraphQL operations over HTTP. * @@ -64,14 +70,18 @@ export class GraphQLClient extends Ability { * * @param query GraphQL document text. * @param variables Variables supplied to the operation. + * @param options Per-request execution options. * @throws Error when the HTTP response is not OK or the GraphQL result contains errors. */ - async execute = Record>(query: string, variables: Record = {}): Promise> { + async execute = Record>(query: string, variables: Record = {}, options: GraphQLExecuteOptions = {}): Promise> { + const requestHeaders = options.headers ?? {}; + const response = await this.fetcher(this.apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', ...this.resolveHeaders(), + ...requestHeaders, }, body: JSON.stringify({ query, variables }), }); diff --git a/packages/ocom-verification/acceptance-api/package.json b/packages/ocom-verification/acceptance-api/package.json index 06e434cb3..4690c16b1 100644 --- a/packages/ocom-verification/acceptance-api/package.json +++ b/packages/ocom-verification/acceptance-api/package.json @@ -30,6 +30,7 @@ "@ocom/application-services": "workspace:*", "@ocom/context-spec": "workspace:*", "@ocom/data-sources-mongoose-models": "workspace:*", + "@ocom/event-handler": "workspace:*", "@ocom/graphql": "workspace:*", "@ocom/persistence": "workspace:*", "@ocom/service-apollo-server": "workspace:*", diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/notes/member-notes.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/notes/member-notes.ts new file mode 100644 index 000000000..d5cc0d99f --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/notes/member-notes.ts @@ -0,0 +1,39 @@ +// export interface MemberDetails { +// memberName: string; +// role?: string; +// email?: string; +// } + +export interface MemberProfileExpectation { + name?: string; + email?: string; + bio?: string; + avatarDocumentId?: string; + interests?: string[]; + showInterests?: boolean; + showEmail?: boolean; + showProfile?: boolean; + showLocation?: boolean; + showProperties?: boolean; +} + +export interface MemberNotes { + communityIdsByName: Record; + roleIdsByCommunityName: Record>; + listedMemberNames: string[]; + endUserIdsByLabel: Record; + lastMemberCommunityId: string; + lastMemberId: string; + lastMemberName: string; + lastMemberRoleName: string; + lastMemberRemoved: boolean; + lastLinkedEndUserId: string; + lastExpectedMemberProfile?: MemberProfileExpectation; + lastMemberProfileEmail?: string; + lastExpectedMemberProfileEmail?: string; + lastMemberStatus: string; + lastValidationError: string; + lastAuthorizationError: string; + principalMemberId: string; + authorizationToken: string; +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/questions/community-id-named.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/community-id-named.ts new file mode 100644 index 000000000..865ab6077 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/community-id-named.ts @@ -0,0 +1,23 @@ +import { type AnswersQuestions, notes, Question, type UsesAbilities } from '@serenity-js/core'; +import type { MemberNotes } from '../notes/member-notes.ts'; + +/** Resolves the ID of a community created earlier in the current scenario. */ +export class CommunityIdNamed extends Question> { + static called(communityName: string): CommunityIdNamed { + return new CommunityIdNamed(communityName); + } + + private constructor(private readonly communityName: string) { + super(`ID of community "${communityName}"`); + } + + override async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise { + const communityIdsByName = await actor.answer(notes().get('communityIdsByName')).catch(() => ({}) as Record); + const communityId = communityIdsByName[this.communityName]; + if (!communityId) { + throw new Error(`Unknown community "${this.communityName}". Ensure it was created in setup.`); + } + + return communityId; + } +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/questions/end-user-id-in-community.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/end-user-id-in-community.ts new file mode 100644 index 000000000..640c4a7d2 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/end-user-id-in-community.ts @@ -0,0 +1,27 @@ +import { GraphQLClient } from '@cellix/serenity-framework/clients/graphql'; +import { type Actor, type AnswersQuestions, Question, type UsesAbilities } from '@serenity-js/core'; +import { END_USERS_BY_COMMUNITY_QUERY } from '../../../shared/graphql/member-operations.ts'; + +export class EndUserIdInCommunity extends Question> { + constructor( + private readonly communityId: string, + private readonly displayName: string, + ) { + super(`end user "${displayName}" in community "${communityId}"`); + } + + static withDisplayName(communityId: string, displayName: string): EndUserIdInCommunity { + return new EndUserIdInCommunity(communityId, displayName); + } + + override async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise { + const graphql = GraphQLClient.as(actor as unknown as Actor); + const response = await graphql.execute(END_USERS_BY_COMMUNITY_QUERY, { communityId: this.communityId }); + const endUsers = (response.data?.['endUsersByCommunityId'] as Array> | undefined) ?? []; + const endUser = endUsers.find((candidate) => String(candidate['displayName'] ?? '') === this.displayName); + if (!endUser?.['id']) { + throw new Error(`End user "${this.displayName}" is not available in community "${this.communityId}"`); + } + return String(endUser['id']); + } +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/questions/has-no-member-for-community.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/has-no-member-for-community.ts new file mode 100644 index 000000000..1c7011ddf --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/has-no-member-for-community.ts @@ -0,0 +1,35 @@ +import { GraphQLClient } from '@cellix/serenity-framework/clients/graphql'; +import { type Actor, type AnswersQuestions, Question, type UsesAbilities } from '@serenity-js/core'; +import { MEMBERS_FOR_CURRENT_END_USER_QUERY } from '../../../shared/graphql/member-operations.ts'; + +interface CurrentEndUserMemberShape { + id?: string; + community?: { + id?: string; + }; +} + +type ExecuteWithRequestOptions = = Record>(query: string, variables?: Record, options?: { headers?: Record }) => Promise<{ data: TData }>; + +export class HasNoMemberForCommunity extends Question> { + static authenticatedWith(authorizationToken: string, communityId: string): HasNoMemberForCommunity { + return new HasNoMemberForCommunity(authorizationToken, communityId); + } + + private constructor( + private readonly authorizationToken: string, + private readonly communityId: string, + ) { + super(`whether the authenticated end user has no member in community "${communityId}"`); + } + + override async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise { + const graphql = GraphQLClient.as(actor as unknown as Actor) as GraphQLClient & { execute: ExecuteWithRequestOptions }; + const response = await graphql.execute(MEMBERS_FOR_CURRENT_END_USER_QUERY, undefined, { + headers: { Authorization: `Bearer ${this.authorizationToken}` }, + }); + const members = (response.data?.['membersForCurrentEndUser'] as CurrentEndUserMemberShape[] | undefined) ?? []; + + return !members.some((member) => String(member.community?.id ?? '') === String(this.communityId)); + } +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-account-linked.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-account-linked.ts new file mode 100644 index 000000000..b1c8e7050 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-account-linked.ts @@ -0,0 +1,38 @@ +import { type AnswersQuestions, Question, type UsesAbilities } from '@serenity-js/core'; +import { MemberById } from './member-by-id.ts'; + +export class MemberAccountLinked extends Question> { + constructor( + private readonly memberId: string, + private readonly endUserId: string, + ) { + super(`whether member "${memberId}" is linked to end user "${endUserId}"`); + } + + static for(memberId: string, endUserId: string): MemberAccountLinked { + return new MemberAccountLinked(memberId, endUserId); + } + + override async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise { + const member = await actor.answer(MemberById.withId(this.memberId)); + return member?.accounts?.some((account) => account.user?.id === this.endUserId) ?? false; + } +} + +export class MemberAccountCount extends Question> { + constructor( + private readonly memberId: string, + private readonly endUserId: string, + ) { + super(`the number of links from member "${memberId}" to end user "${endUserId}"`); + } + + static for(memberId: string, endUserId: string): MemberAccountCount { + return new MemberAccountCount(memberId, endUserId); + } + + override async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise { + const member = await actor.answer(MemberById.withId(this.memberId)); + return member?.accounts?.filter((account) => account.user?.id === this.endUserId).length ?? 0; + } +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-by-id.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-by-id.ts new file mode 100644 index 000000000..5165e588a --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-by-id.ts @@ -0,0 +1,83 @@ +import { GraphQLClient } from '@cellix/serenity-framework/clients/graphql'; +import { type Actor, type AnswersQuestions, Question, type UsesAbilities } from '@serenity-js/core'; +import { MEMBER_BY_ID_QUERY } from '../../../shared/graphql/member-operations.ts'; + +export interface MemberByIdResult { + id?: string; + memberName?: string; + community?: { + id?: string; + }; + accounts?: Array<{ + user?: { + id?: string; + }; + }>; + profile?: { + name?: string; + email?: string; + bio?: string; + avatarDocumentId?: string; + interests?: string[]; + showInterests?: boolean; + showEmail?: boolean; + showProfile?: boolean; + showLocation?: boolean; + showProperties?: boolean; + }; +} + +export class MemberById extends Question> { + constructor(private readonly memberId: string) { + super(`member by id "${memberId}"`); + } + + static withId(memberId: string): MemberById { + return new MemberById(memberId); + } + + override async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise { + const graphql = GraphQLClient.as(actor as unknown as Actor); + const response = await graphql.execute(MEMBER_BY_ID_QUERY, { + id: this.memberId, + }); + + const member = response.data?.['member'] as Record | undefined; + if (!member) { + return undefined; + } + + const profile = member['profile'] as Record | undefined; + const accounts = Array.isArray(member['accounts']) + ? (member['accounts'] as Array>).map((account) => ({ + user: { + id: (account['user'] as Record | undefined)?.['id'] !== undefined ? String((account['user'] as Record)['id']) : undefined, + }, + })) + : undefined; + const interests = Array.isArray(profile?.['interests']) ? (profile?.['interests'] as Array).map((value) => String(value)).filter((value) => value.length > 0) : undefined; + + return { + id: member['id'] !== undefined ? String(member['id']) : undefined, + memberName: member['memberName'] !== undefined ? String(member['memberName']) : undefined, + community: { + id: (member['community'] as Record | undefined)?.['id'] !== undefined ? String((member['community'] as Record)['id']) : undefined, + }, + accounts, + profile: profile + ? { + ...(profile['name'] !== undefined ? { name: String(profile['name'] ?? '') } : {}), + ...(profile['email'] !== undefined ? { email: String(profile['email'] ?? '') } : {}), + ...(profile['bio'] !== undefined ? { bio: String(profile['bio'] ?? '') } : {}), + ...(profile['avatarDocumentId'] !== undefined ? { avatarDocumentId: String(profile['avatarDocumentId'] ?? '') } : {}), + ...(interests !== undefined ? { interests } : {}), + ...(profile['showInterests'] !== undefined ? { showInterests: Boolean(profile['showInterests']) } : {}), + ...(profile['showEmail'] !== undefined ? { showEmail: Boolean(profile['showEmail']) } : {}), + ...(profile['showProfile'] !== undefined ? { showProfile: Boolean(profile['showProfile']) } : {}), + ...(profile['showLocation'] !== undefined ? { showLocation: Boolean(profile['showLocation']) } : {}), + ...(profile['showProperties'] !== undefined ? { showProperties: Boolean(profile['showProperties']) } : {}), + } + : undefined, + }; + } +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-listed-in-community.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-listed-in-community.ts new file mode 100644 index 000000000..10ac006fc --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-listed-in-community.ts @@ -0,0 +1,23 @@ +import { GraphQLClient } from '@cellix/serenity-framework/clients/graphql'; +import { type Actor, type AnswersQuestions, Question, type UsesAbilities } from '@serenity-js/core'; +import { MEMBERS_BY_COMMUNITY_QUERY } from '../../../shared/graphql/member-operations.ts'; + +export class MemberListedInCommunity extends Question> { + static named(memberName: string, communityId: string): MemberListedInCommunity { + return new MemberListedInCommunity(memberName, communityId); + } + + private constructor( + private readonly memberName: string, + private readonly communityId: string, + ) { + super(`whether member "${memberName}" is listed in community "${communityId}"`); + } + + override async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise { + const graphql = GraphQLClient.as(actor as unknown as Actor); + const response = await graphql.execute(MEMBERS_BY_COMMUNITY_QUERY, { communityId: this.communityId }); + const members = response.data?.['membersByCommunityId']; + return Array.isArray(members) && members.some((member) => (member as Record)['memberName'] === this.memberName); + } +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-role-name.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-role-name.ts new file mode 100644 index 000000000..8b1ff44e9 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-role-name.ts @@ -0,0 +1,17 @@ +import { type AnswersQuestions, notes, Question, type UsesAbilities } from '@serenity-js/core'; +import type { MemberNotes } from '../notes/member-notes.ts'; + +export class MemberRoleName extends Question> { + static fromLastUpdate(): MemberRoleName { + return new MemberRoleName(); + } + + private constructor() { + super('role name returned by the member update'); + } + + override async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise { + const roleName = await actor.answer(notes().get('lastMemberRoleName')); + return roleName || null; + } +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-visible-in-list.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-visible-in-list.ts new file mode 100644 index 000000000..2f652e72d --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-visible-in-list.ts @@ -0,0 +1,17 @@ +import { type AnswersQuestions, notes, Question } from '@serenity-js/core'; +import type { MemberNotes } from '../notes/member-notes.ts'; + +export class MemberVisibleInList extends Question> { + static named(memberName: string): MemberVisibleInList { + return new MemberVisibleInList(memberName); + } + + private constructor(private readonly memberName: string) { + super(`whether member "${memberName}" is visible in the member list`); + } + + override async answeredBy(actor: AnswersQuestions): Promise { + const memberNames = await actor.answer(notes().get('listedMemberNames')); + return memberNames.includes(this.memberName); + } +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/questions/principal-member-id-for-community.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/principal-member-id-for-community.ts new file mode 100644 index 000000000..b53c861e7 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/questions/principal-member-id-for-community.ts @@ -0,0 +1,45 @@ +import { GraphQLClient } from '@cellix/serenity-framework/clients/graphql'; +import { type Actor, type AnswersQuestions, Question, type UsesAbilities } from '@serenity-js/core'; +import { MEMBERS_FOR_CURRENT_END_USER_QUERY } from '../../../shared/graphql/member-operations.ts'; + +interface CurrentEndUserMemberShape { + id?: string; + community?: { + id?: string; + }; +} + +const PRINCIPAL_MEMBER_LOOKUP_MAX_ATTEMPTS = 20; +const PRINCIPAL_MEMBER_LOOKUP_DELAY_MS = 150; + +export class PrincipalMemberIdForCommunity extends Question> { + constructor(private readonly communityId: string) { + super(`principal member id for community "${communityId}"`); + } + + static inCommunity(communityId: string): PrincipalMemberIdForCommunity { + return new PrincipalMemberIdForCommunity(communityId); + } + + override async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise { + const graphql = GraphQLClient.as(actor as unknown as Actor); + + for (let attempt = 1; attempt <= PRINCIPAL_MEMBER_LOOKUP_MAX_ATTEMPTS; attempt++) { + const response = await graphql.execute(MEMBERS_FOR_CURRENT_END_USER_QUERY); + const members = (response.data?.['membersForCurrentEndUser'] as CurrentEndUserMemberShape[] | undefined) ?? []; + const principalMember = members.find((member) => String(member.community?.id ?? '') === String(this.communityId)); + + if (principalMember?.id) { + return String(principalMember.id); + } + + await wait(PRINCIPAL_MEMBER_LOOKUP_DELAY_MS); + } + + throw new Error(`No provisioned creator member found for community "${this.communityId}" after waiting ${PRINCIPAL_MEMBER_LOOKUP_MAX_ATTEMPTS * PRINCIPAL_MEMBER_LOOKUP_DELAY_MS}ms`); + } +} + +function wait(delayMs: number): Promise { + return new Promise((resolve) => setTimeout(resolve, delayMs)); +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/assign-member-account.steps.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/assign-member-account.steps.ts new file mode 100644 index 000000000..8a9c65613 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/assign-member-account.steps.ts @@ -0,0 +1,64 @@ +import { Given, Then, When } from '@cucumber/cucumber'; +import { actors } from '@ocom-verification/verification-shared/test-data'; +import { actorCalled, actorInTheSpotlight, notes } from '@serenity-js/core'; +import type { MemberNotes } from '../notes/member-notes.ts'; +import { CommunityIdNamed } from '../questions/community-id-named.ts'; +import { EndUserIdInCommunity } from '../questions/end-user-id-in-community.ts'; +import { MemberAccountCount, MemberAccountLinked } from '../questions/member-account-linked.ts'; +import { AssignMemberAccount } from '../tasks/assign-member-account.ts'; + +const accountDisplayNames: Record = { + Charlie: `${actors.CommunityOwner.givenName} ${actors.CommunityOwner.familyName}`, +}; + +Given('end-user account {string} is available for assignment in {string}', async (accountLabel: string, communityName: string) => { + const actor = actorInTheSpotlight(); + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + const displayName = accountDisplayNames[accountLabel]; + if (!displayName) { + throw new Error(`Unknown community or end-user account label: "${communityName}" / "${accountLabel}"`); + } + const endUserId = await actor.answer(EndUserIdInCommunity.withDisplayName(communityId, displayName)); + const idsByLabel = await actor.answer(notes().get('endUserIdsByLabel')).catch(() => ({}) as Record); + await actor.attemptsTo(notes().set('endUserIdsByLabel', { ...idsByLabel, [accountLabel]: endUserId })); +}); + +When('{word} associates end-user account {string} to member {string} in {string}', async (actorName: string, accountLabel: string, _memberName: string, communityName: string) => { + const actor = actorCalled(actorName); + const endUserIds = await actor.answer(notes().get('endUserIdsByLabel')); + const memberId = await actor.answer(notes().get('lastMemberId')); + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + await actor.attemptsTo(notes().set('lastValidationError', undefined as unknown as string)); + try { + await actor.attemptsTo(AssignMemberAccount.to({ communityId, memberId, endUserId: endUserIds[accountLabel] ?? '' })); + } catch (error) { + await actor.attemptsTo(notes().set('lastValidationError', error instanceof Error ? error.message : String(error))); + } +}); + +Given('member {string} is already linked to end-user account {string}', async (_memberName: string, accountLabel: string) => { + const actor = actorInTheSpotlight(); + const communityId = await actor.answer(notes().get('lastMemberCommunityId')); + const memberId = await actor.answer(notes().get('lastMemberId')); + const endUserIds = await actor.answer(notes().get('endUserIdsByLabel')); + await actor.attemptsTo(AssignMemberAccount.to({ communityId, memberId, endUserId: endUserIds[accountLabel] ?? '' })); +}); + +Then('member {string} should be linked to end-user account {string}', async (_memberName: string, accountLabel: string) => { + const actor = actorInTheSpotlight(); + const memberId = await actor.answer(notes().get('lastMemberId')); + const endUserIds = await actor.answer(notes().get('endUserIdsByLabel')); + if (!(await actor.answer(MemberAccountLinked.for(memberId, endUserIds[accountLabel] ?? '')))) { + throw new Error(`Expected member "${memberId}" to be linked to end-user account "${accountLabel}"`); + } +}); + +Then('member {string} should remain linked to end-user account {string} only once', async (_memberName: string, accountLabel: string) => { + const actor = actorInTheSpotlight(); + const memberId = await actor.answer(notes().get('lastMemberId')); + const endUserIds = await actor.answer(notes().get('endUserIdsByLabel')); + const count = await actor.answer(MemberAccountCount.for(memberId, endUserIds[accountLabel] ?? '')); + if (count !== 1) { + throw new Error(`Expected one account association for "${accountLabel}" but found ${count}`); + } +}); diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/create-member.steps.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/create-member.steps.ts new file mode 100644 index 000000000..2805fdaa8 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/create-member.steps.ts @@ -0,0 +1,109 @@ +import { GherkinDataTable } from '@cellix/serenity-framework/cucumber/gherkin-data-table'; +import { type DataTable, Given, Then, When } from '@cucumber/cucumber'; +import { actors } from '@ocom-verification/verification-shared/test-data'; +import { Ensure, equals, isPresent } from '@serenity-js/assertions'; +import { actorCalled, notes } from '@serenity-js/core'; +import { LastGraphQLResponse } from '../../../shared/questions/last-graphql-response.ts'; +import type { MemberNotes } from '../notes/member-notes.ts'; +import { CommunityIdNamed } from '../questions/community-id-named.ts'; +import { MemberById } from '../questions/member-by-id.ts'; +import { PrincipalMemberIdForCommunity } from '../questions/principal-member-id-for-community.ts'; +import { CreateCommunity } from '../tasks/create-community.ts'; +import { CreateMember } from '../tasks/create-member.ts'; + +let lastActorName = actors.CommunityOwner.name; + +interface MemberDetails { + memberName?: string; + email?: string; +} + +Given('{word} is signed in as a community owner for member management', (actorName: string) => { + lastActorName = actorName; + actorCalled(actorName); +}); + +Given('{word} has a community named {string}', async (actorName: string, communityName: string) => { + lastActorName = actorName; + + const actor = actorCalled(actorName); + await actor.attemptsTo(CreateCommunity.withName(communityName)); + + const communityId = (await actor.answer(notes().get('lastCommunityId'))) as string; + const existing = await actor.answer(notes().get('communityIdsByName')).catch(() => ({}) as Record); + + await actor.attemptsTo( + notes().set('communityIdsByName', { + ...existing, + [communityName]: communityId, + }), + ); +}); + +When('{word} creates a member in {string} with:', async (actorName: string, communityName: string, dataTable: DataTable) => { + lastActorName = actorName; + + const actor = actorCalled(actorName); + const details = GherkinDataTable.from(dataTable).rowsHash(); + + const memberName = details.memberName?.trim() ?? ''; + + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + + const principalMemberId = await actor.answer(PrincipalMemberIdForCommunity.inCommunity(communityId)); + await actor.attemptsTo(CreateMember({ memberName, communityId, principalMemberId })); +}); + +When('{word} attempts to create a member in {string} with:', async (actorName: string, communityName: string, dataTable: DataTable) => { + lastActorName = actorName; + const actor = actorCalled(actorName); + const details = GherkinDataTable.from(dataTable).rowsHash(); + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + + await actor.attemptsTo(notes().set('lastMemberId', undefined as unknown as string), notes().set('lastValidationError', undefined as unknown as string)); + + try { + const principalMemberId = await actor.answer(PrincipalMemberIdForCommunity.inCommunity(communityId)); + await actor.attemptsTo(CreateMember({ memberName: details.memberName?.trim() ?? '', communityId, principalMemberId })); + } catch (error) { + await actor.attemptsTo(notes().set('lastValidationError', error instanceof Error ? error.message : String(error))); + } +}); + +Then('the member should be created successfully in {string}', async (communityName: string) => { + const actor = actorCalled(lastActorName); + await actor.attemptsTo(Ensure.that(LastGraphQLResponse.field('memberCreate.status.success'), equals(true)), Ensure.that(LastGraphQLResponse.field('memberCreate.member.id'), isPresent())); + + const memberId = await actor.answer(LastGraphQLResponse.field('memberCreate.member.id')); + const memberName = await actor.answer(notes().get('lastMemberName')); + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + const persistedMember = await actor.answer(MemberById.withId(memberId)); + + await actor.attemptsTo( + Ensure.that(persistedMember, isPresent()), + Ensure.that(persistedMember?.id, equals(memberId)), + Ensure.that(persistedMember?.memberName, equals(memberName)), + Ensure.that(persistedMember?.community?.id, equals(communityId)), + ); +}); + +Then('she should see a member error for {string}', async (fieldName: string) => { + const actor = actorCalled(lastActorName); + const responseError = await actor.answer(LastGraphQLResponse.field('memberCreate.status.errorMessage')).catch(() => ''); + const capturedError = await actor.answer(notes().get('lastValidationError')).catch(() => ''); + const error = responseError || capturedError; + const isFieldMentioned = error.toLowerCase().includes(fieldName.toLowerCase()); + if (!error || (!isFieldMentioned && !/cannot be empty|required|missing|invalid|must not be empty|too short|too long|already associated/i.test(error))) { + throw new Error(`Expected a validation error related to "${fieldName}", but got: "${error}"`); + } +}); + +Then('no new member should be created in {string}', async (_communityName: string) => { + const actor = actorCalled(lastActorName); + const memberId = await actor.answer(notes().get('lastMemberId')).catch(() => ''); + const success = await actor.answer(LastGraphQLResponse.field('memberCreate.status.success')).catch(() => undefined); + const capturedError = await actor.answer(notes().get('lastValidationError')).catch(() => ''); + if (memberId || success === true || (success === undefined && !capturedError)) { + throw new Error('Expected member creation to be blocked by validation'); + } +}); diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/index.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/index.ts index c04c54d61..47733d53d 100644 --- a/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/index.ts +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/index.ts @@ -1,2 +1,8 @@ // Community context step definitions import './create-community.steps.ts'; +import './create-member.steps.ts'; +import './list-members.steps.ts'; +import './member-role.steps.ts'; +import './remove-member.steps.ts'; +import './assign-member-account.steps.ts'; +import './update-member.steps.ts'; diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/list-members.steps.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/list-members.steps.ts new file mode 100644 index 000000000..519efdec1 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/list-members.steps.ts @@ -0,0 +1,69 @@ +import { type DataTable, Given, Then, When } from '@cucumber/cucumber'; +import { actorCalled, actorInTheSpotlight, notes } from '@serenity-js/core'; +import type { MemberNotes } from '../notes/member-notes.ts'; +import { CommunityIdNamed } from '../questions/community-id-named.ts'; +import { MemberVisibleInList } from '../questions/member-visible-in-list.ts'; +import { PrincipalMemberIdForCommunity } from '../questions/principal-member-id-for-community.ts'; +import { CreateMember } from '../tasks/create-member.ts'; +import { ListMembers } from '../tasks/list-members.ts'; + +Given('{word} is an authenticated community admin for {string}', async (actorName: string, communityName: string) => { + const owner = actorInTheSpotlight(); + await owner.answer(CommunityIdNamed.called(communityName)); + const communityIdsByName = await owner.answer(notes().get('communityIdsByName')); + + await actorCalled(actorName).attemptsTo(notes().set('communityIdsByName', communityIdsByName)); +}); + +Given('the following members exist in {string}:', async (communityName: string, dataTable: DataTable) => { + const actor = actorInTheSpotlight(); + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + + for (const details of dataTable.hashes()) { + const { memberName } = details; + if (!memberName) { + throw new Error('memberName is required when creating listed members'); + } + const principalMemberId = await actor.answer(PrincipalMemberIdForCommunity.inCommunity(communityId)); + await actor.attemptsTo(CreateMember({ memberName: memberName.trim(), communityId, principalMemberId })); + } +}); + +When('{word} lists members for {string}', async (actorName: string, communityName: string) => { + const actor = actorCalled(actorName); + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + + await actor.attemptsTo(ListMembers.inCommunity(communityId)); +}); + +When('{word} searches the member list in {string} for {string}', async (actorName: string, communityName: string, searchTerm: string) => { + const actor = actorCalled(actorName); + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + + await actor.attemptsTo(ListMembers.inCommunity(communityId, searchTerm)); +}); + +Then('{word} should see the following members in {string}:', async (actorName: string, _communityName: string, dataTable: DataTable) => { + const actor = actorCalled(actorName); + for (const details of dataTable.hashes()) { + const { memberName } = details; + if (!memberName) { + throw new Error('memberName is required when verifying listed members'); + } + if (!(await actor.answer(MemberVisibleInList.named(memberName)))) { + throw new Error(`Expected member "${memberName}" to appear in the member list`); + } + } +}); + +Then('{word} should not see member {string} from {string}', async (actorName: string, memberName: string, _communityName: string) => { + if (await actorCalled(actorName).answer(MemberVisibleInList.named(memberName))) { + throw new Error(`Expected member "${memberName}" not to appear in the member list`); + } +}); + +Then('{word} should not see member {string} in the filtered results', async (actorName: string, memberName: string) => { + if (await actorCalled(actorName).answer(MemberVisibleInList.named(memberName))) { + throw new Error(`Expected member "${memberName}" not to appear in the filtered member list`); + } +}); diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/member-role.steps.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/member-role.steps.ts new file mode 100644 index 000000000..30b8f6667 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/member-role.steps.ts @@ -0,0 +1,52 @@ +import { Given, Then, When } from '@cucumber/cucumber'; +import { actors } from '@ocom-verification/verification-shared/test-data'; +import { actorCalled, actorInTheSpotlight, notes } from '@serenity-js/core'; +import type { MemberNotes } from '../notes/member-notes.ts'; +import { CommunityIdNamed } from '../questions/community-id-named.ts'; +import { MemberRoleName } from '../questions/member-role-name.ts'; +import { SeedEndUserRole } from '../tasks/seed-end-user-role.ts'; +import { UpdateMemberRole } from '../tasks/update-member-role.ts'; + +let lastActorName = actors.CommunityOwner.name; + +Given('a role {string} exists in {string}', async (roleName: string, communityName: string) => { + const actor = actorInTheSpotlight(); + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + await actor.attemptsTo(SeedEndUserRole.named(roleName, communityName, communityId)); +}); + +When('{word} changes member {string} in {string} to role {string}', async (actorName: string, _memberName: string, communityName: string, roleName: string) => { + lastActorName = actorName; + const actor = actorCalled(actorName); + const roleIds = await actor.answer(notes().get('roleIdsByCommunityName')); + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + const roleId = roleIds[communityName]?.[roleName]; + if (!roleId) throw new Error(`Missing role "${roleName}" in "${communityName}"`); + await actor.attemptsTo(UpdateMemberRole.with(roleId, communityId)); +}); + +When('{word} attempts to change member {string} in {string} to role {string}', async (actorName: string, _memberName: string, communityName: string, roleName: string) => { + lastActorName = actorName; + const actor = actorCalled(actorName); + const roleIds = await actor.answer(notes().get('roleIdsByCommunityName')); + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + const roleId = Object.values(roleIds) + .map((roles) => roles[roleName]) + .find(Boolean); + if (!roleId) throw new Error(`Missing role "${roleName}"`); + try { + await actor.attemptsTo(UpdateMemberRole.with(roleId, communityId)); + } catch (error) { + await actor.attemptsTo(notes().set('lastValidationError', error instanceof Error ? error.message : String(error))); + } +}); + +Then('member {string} should have role {string} in {string}', async (_memberName: string, roleName: string, _communityName: string) => { + const actor = actorCalled(lastActorName); + if ((await actor.answer(MemberRoleName.fromLastUpdate())) !== roleName) throw new Error(`Expected member role "${roleName}"`); +}); + +Then('member {string} should not have role {string} in {string}', async (_memberName: string, roleName: string, _communityName: string) => { + const actor = actorCalled(lastActorName); + if ((await actor.answer(MemberRoleName.fromLastUpdate()).catch(() => null)) === roleName) throw new Error(`Expected member not to have role "${roleName}"`); +}); diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/remove-member.steps.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/remove-member.steps.ts new file mode 100644 index 000000000..1d634071e --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/remove-member.steps.ts @@ -0,0 +1,91 @@ +import { Given, Then, When } from '@cucumber/cucumber'; +import { actors } from '@ocom-verification/verification-shared/test-data'; +import { actorCalled, actorInTheSpotlight, notes } from '@serenity-js/core'; +import type { MemberNotes } from '../notes/member-notes.ts'; +import { CommunityIdNamed } from '../questions/community-id-named.ts'; +import { HasNoMemberForCommunity } from '../questions/has-no-member-for-community.ts'; +import { MemberListedInCommunity } from '../questions/member-listed-in-community.ts'; +import { RemoveMember } from '../tasks/remove-member.ts'; + +let lastActorName = actors.CommunityOwner.name; +let managementOwnerActorName = actors.CommunityOwner.name; + +Given('{word} is signed in without membership in {string}', async (actorName: string, communityName: string) => { + const owner = actorInTheSpotlight(); + managementOwnerActorName = owner.name; + const communityId = await owner.answer(CommunityIdNamed.called(communityName)); + const communityIds = await owner.answer(notes().get('communityIdsByName')); + const targetMemberId = await owner.answer(notes().get('lastMemberId')); + const targetMemberName = await owner.answer(notes().get('lastMemberName')); + + const actor = actorCalled(actorName); + const authorizationToken = actors.CommunityMember.email; + if (!(await actor.answer(HasNoMemberForCommunity.authenticatedWith(authorizationToken, communityId)))) { + throw new Error(`Expected ${actorName} to have no membership in community "${communityName}"`); + } + await actor.attemptsTo( + notes().set('communityIdsByName', communityIds), + notes().set('lastMemberId', targetMemberId), + notes().set('lastMemberName', targetMemberName), + notes().set('lastMemberCommunityId', communityId), + notes().set('principalMemberId', targetMemberId), + notes().set('authorizationToken', authorizationToken), + notes().set('lastAuthorizationError', undefined as unknown as string), + ); +}); + +When('{word} removes member {string} from {string}', async (actorName: string, _memberName: string, communityName: string) => { + lastActorName = actorName; + const actor = actorCalled(actorName); + const memberId = await actor.answer(notes().get('lastMemberId')); + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + if (!memberId) { + throw new Error(`Missing member or community state for removal from "${communityName}"`); + } + await actor.attemptsTo(notes().set('lastMemberRemoved', false), RemoveMember.withId(memberId, communityId)); +}); + +Then('the member should be removed successfully from {string}', async (_communityName: string) => { + const actor = actorCalled(lastActorName); + const removed = await actor.answer(notes().get('lastMemberRemoved')); + if (!removed) { + throw new Error('Expected member removal to succeed'); + } +}); + +Then('member {string} should not appear in member listings for {string}', async (memberName: string, communityName: string) => { + const actor = actorCalled(lastActorName); + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + if (await actor.answer(MemberListedInCommunity.named(memberName, communityId))) { + throw new Error(`Expected member "${memberName}" not to appear in listings for "${communityName}"`); + } +}); + +When('{word} attempts to remove member {string} from {string}', async (actorName: string, _memberName: string, communityName: string) => { + lastActorName = actorName; + const actor = actorCalled(actorName); + const memberId = await actor.answer(notes().get('lastMemberId')); + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + try { + await actor.attemptsTo(RemoveMember.withId(memberId, communityId)); + } catch (error) { + await actor.attemptsTo(notes().set('lastAuthorizationError', error instanceof Error ? error.message : String(error))); + } +}); + +Then('{word} should receive an authorization error for member management', async (actorName: string) => { + const error = await actorCalled(actorName) + .answer(notes().get('lastAuthorizationError')) + .catch(() => ''); + if (!/permission|cannot remove|unauthorized|forbidden|not a member/i.test(error)) { + throw new Error(`Expected a member-management authorization error, but got: "${error}"`); + } +}); + +Then('member {string} should remain in {string}', async (memberName: string, communityName: string) => { + const owner = actorCalled(managementOwnerActorName); + const communityId = await owner.answer(CommunityIdNamed.called(communityName)); + if (!(await owner.answer(MemberListedInCommunity.named(memberName, communityId)))) { + throw new Error(`Expected member "${memberName}" to remain in "${communityName}"`); + } +}); diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/update-member.steps.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/update-member.steps.ts new file mode 100644 index 000000000..1da721cc6 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/update-member.steps.ts @@ -0,0 +1,127 @@ +import { GherkinDataTable } from '@cellix/serenity-framework/cucumber/gherkin-data-table'; +import { type DataTable, Then, When } from '@cucumber/cucumber'; +import { actors } from '@ocom-verification/verification-shared/test-data'; +import { actorCalled, notes } from '@serenity-js/core'; +import type { MemberNotes, MemberProfileExpectation } from '../notes/member-notes.ts'; +import { CommunityIdNamed } from '../questions/community-id-named.ts'; +import { MemberById, type MemberByIdResult } from '../questions/member-by-id.ts'; +import { UpdateMember } from '../tasks/update-member-profile.ts'; + +let lastActorName = actors.CommunityOwner.name; + +interface MemberProfileUpdateDetails { + name?: string; + memberName?: string; + email?: string; + bio?: string; + avatarDocumentId?: string; + interests?: string; + showInterests?: string; + showEmail?: string; + showProfile?: string; + showLocation?: string; + showProperties?: string; +} + +When('{word} updates member {string} in {string} with:', async (actorName: string, _memberName: string, communityName: string, dataTable: DataTable) => { + lastActorName = actorName; + + const actor = actorCalled(actorName); + const details = GherkinDataTable.from(dataTable).rowsHash(); + const communityId = await actor.answer(CommunityIdNamed.called(communityName)); + + const expectedProfile: MemberProfileExpectation = { + ...(details.name ? { name: details.name } : {}), + ...(details.memberName ? { name: details.memberName } : {}), + ...(details.email ? { email: details.email } : {}), + ...(details.bio ? { bio: details.bio } : {}), + ...(details.avatarDocumentId ? { avatarDocumentId: details.avatarDocumentId } : {}), + ...(details.interests + ? { + interests: details.interests + .split(',') + .map((interest) => interest.trim()) + .filter((interest) => interest.length > 0), + } + : {}), + ...(details.showInterests !== undefined ? { showInterests: details.showInterests.toLowerCase() === 'true' } : {}), + ...(details.showEmail !== undefined ? { showEmail: details.showEmail.toLowerCase() === 'true' } : {}), + ...(details.showProfile !== undefined ? { showProfile: details.showProfile.toLowerCase() === 'true' } : {}), + ...(details.showLocation !== undefined ? { showLocation: details.showLocation.toLowerCase() === 'true' } : {}), + ...(details.showProperties !== undefined ? { showProperties: details.showProperties.toLowerCase() === 'true' } : {}), + }; + + await actor.attemptsTo(notes().set('lastValidationError', undefined as unknown as string), notes().set('lastExpectedMemberProfile', expectedProfile)); + await actor.attemptsTo( + UpdateMember.with({ + communityId, + profile: expectedProfile, + }), + ); +}); + +Then('the member should be updated successfully in {string}', async (communityName: string) => { + const actor = actorCalled(lastActorName); + + const status = await actor.answer(notes().get('lastMemberStatus')); + const memberId = await actor.answer(notes().get('lastMemberId')); + const validationError = await actor.answer(notes().get('lastValidationError')); + const expectedCommunityId = await actor.answer(CommunityIdNamed.called(communityName)); + + if (validationError) { + throw new Error(`Expected member update to succeed for "${communityName}", but got validation error: "${validationError}"`); + } + + if (status !== 'SUCCESS') { + throw new Error(`Expected member status "SUCCESS" but got "${status}"`); + } + + if (!memberId) { + throw new Error(`Expected an updated member id for "${communityName}" but none was recorded`); + } + + const updatedMember = await actor.answer(MemberById.withId(memberId)); + if (!updatedMember) { + throw new Error(`Expected member "${memberId}" to exist after update, but no member was returned by API`); + } + + if (String(updatedMember.community?.id ?? '') !== String(expectedCommunityId)) { + throw new Error(`Expected updated member to belong to "${communityName}"`); + } + + const expectedProfile = await actor.answer(notes().get('lastExpectedMemberProfile')).catch(() => undefined); + if (!expectedProfile) { + return; + } + + const actualProfile = updatedMember.profile; + if (!actualProfile) { + throw new Error('Expected updated member profile to be returned by API, but profile was missing'); + } + + assertMemberProfileMatches(expectedProfile, actualProfile); +}); + +function assertMemberProfileMatches(expectedProfile: MemberProfileExpectation, actualProfile: NonNullable): void { + const comparableFields: Array> = ['name', 'email', 'bio', 'avatarDocumentId', 'showInterests', 'showEmail', 'showProfile', 'showLocation', 'showProperties']; + + for (const field of comparableFields) { + const expectedValue = expectedProfile[field]; + if (expectedValue === undefined) { + continue; + } + + const actualValue = actualProfile[field]; + if (actualValue !== expectedValue) { + throw new Error(`Expected profile ${field} to be "${String(expectedValue)}" but got "${String(actualValue ?? '')}"`); + } + } + + if (expectedProfile.interests !== undefined) { + const expectedInterests = JSON.stringify(expectedProfile.interests); + const actualInterests = JSON.stringify(actualProfile.interests ?? []); + if (actualInterests !== expectedInterests) { + throw new Error(`Expected profile interests ${expectedInterests} but got ${actualInterests}`); + } + } +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/assign-member-account.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/assign-member-account.ts new file mode 100644 index 000000000..87a5833f9 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/assign-member-account.ts @@ -0,0 +1,26 @@ +import { type Actor, notes, Task } from '@serenity-js/core'; +import { AssignMemberAccount as AssignMemberAccountAbility } from '../../../shared/abilities/assign-member-account.ts'; +import type { MemberNotes } from '../notes/member-notes.ts'; +import { PrincipalMemberIdForCommunity } from '../questions/principal-member-id-for-community.ts'; + +interface AssignmentDetails { + communityId: string; + memberId: string; + endUserId: string; +} + +export class AssignMemberAccount extends Task { + static to(details: AssignmentDetails): AssignMemberAccount { + return new AssignMemberAccount(details); + } + + private constructor(private readonly details: AssignmentDetails) { + super('assigns an end-user account to a member'); + } + + override async performAs(actor: Actor): Promise { + const principalMemberId = await actor.answer(PrincipalMemberIdForCommunity.inCommunity(this.details.communityId)); + await AssignMemberAccountAbility.as(actor).performAs(actor, { ...this.details, principalMemberId }); + await actor.attemptsTo(notes().set('lastLinkedEndUserId', this.details.endUserId)); + } +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/create-member.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/create-member.ts new file mode 100644 index 000000000..a40fd9f7a --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/create-member.ts @@ -0,0 +1,24 @@ +import { notes, Task } from '@serenity-js/core'; +import { MEMBER_CREATE_MUTATION } from '../../../shared/graphql/member-operations.ts'; +import { ExecuteGraphQL } from '../../../shared/interactions/execute-graphql.ts'; +import { LastGraphQLResponse } from '../../../shared/questions/last-graphql-response.ts'; +import type { MemberNotes } from '../notes/member-notes.ts'; + +interface CreateMemberDetails { + memberName: string; + communityId: string; + principalMemberId: string; +} + +export const CreateMember = (details: CreateMemberDetails): Task => + Task.where( + `#actor creates a member named "${details.memberName}"`, + ExecuteGraphQL.operation( + MEMBER_CREATE_MUTATION, + { input: { memberName: details.memberName, communityId: details.communityId } }, + { headers: { 'x-community-id': details.communityId, 'x-member-id': details.principalMemberId } }, + ), + notes().set('lastMemberId', LastGraphQLResponse.field('memberCreate.member.id')), + notes().set('lastMemberCommunityId', details.communityId), + notes().set('lastMemberName', LastGraphQLResponse.field('memberCreate.member.memberName')), + ); diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/list-members.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/list-members.ts new file mode 100644 index 000000000..9a9752ff9 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/list-members.ts @@ -0,0 +1,29 @@ +import { type Actor, notes, Task } from '@serenity-js/core'; +import { ListMembers as ListMembersAbility } from '../../../shared/abilities/list-members.ts'; +import type { MemberNotes } from '../notes/member-notes.ts'; +import { PrincipalMemberIdForCommunity } from '../questions/principal-member-id-for-community.ts'; + +export class ListMembers extends Task { + static inCommunity(communityId: string, searchTerm = ''): ListMembers { + return new ListMembers(communityId, searchTerm); + } + + private constructor( + private readonly communityId: string, + private readonly searchTerm: string, + ) { + super(`lists members in community "${communityId}"`); + } + + async performAs(actor: Actor): Promise { + const principalMemberId = await actor.answer(PrincipalMemberIdForCommunity.inCommunity(this.communityId)); + const members = await ListMembersAbility.as(actor).performAs(actor, { + communityId: this.communityId, + principalMemberId, + }); + const normalizedSearch = this.searchTerm.trim().toLowerCase(); + const listedMemberNames = members.map((member) => member.memberName).filter((name) => !normalizedSearch || name.toLowerCase().includes(normalizedSearch)); + + await actor.attemptsTo(notes().set('listedMemberNames', listedMemberNames)); + } +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/remove-member.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/remove-member.ts new file mode 100644 index 000000000..7e966abc6 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/remove-member.ts @@ -0,0 +1,29 @@ +import { type Actor, notes, Task } from '@serenity-js/core'; +import { RemoveMember as RemoveMemberAbility } from '../../../shared/abilities/remove-member.ts'; +import type { MemberNotes } from '../notes/member-notes.ts'; +import { PrincipalMemberIdForCommunity } from '../questions/principal-member-id-for-community.ts'; + +export class RemoveMember extends Task { + static withId(memberId: string, communityId: string): RemoveMember { + return new RemoveMember(memberId, communityId); + } + + private constructor( + private readonly memberId: string, + private readonly communityId: string, + ) { + super(`removes member "${memberId}"`); + } + + async performAs(actor: Actor): Promise { + const principalMemberId = await actor.answer(notes().get('principalMemberId')).catch(() => actor.answer(PrincipalMemberIdForCommunity.inCommunity(this.communityId))); + const authorizationToken = await actor.answer(notes().get('authorizationToken')).catch(() => undefined); + await RemoveMemberAbility.as(actor).performAs(actor, { + memberId: this.memberId, + communityId: this.communityId, + principalMemberId, + ...(authorizationToken ? { authorizationToken } : {}), + }); + await actor.attemptsTo(notes().set('lastMemberRemoved', true), notes().set('lastMemberStatus', 'REMOVED')); + } +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/seed-end-user-role.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/seed-end-user-role.ts new file mode 100644 index 000000000..7fd865431 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/seed-end-user-role.ts @@ -0,0 +1,29 @@ +import { seedEndUserRole } from '@ocom-verification/verification-shared/test-data'; +import { type Actor, notes, Task } from '@serenity-js/core'; +import { mongoDbName, testMongoServer } from '../../../servers/test-mongo-server.ts'; +import type { MemberNotes } from '../notes/member-notes.ts'; + +export class SeedEndUserRole extends Task { + static named(roleName: string, communityName: string, communityId: string): SeedEndUserRole { + return new SeedEndUserRole(roleName, communityName, communityId); + } + + private constructor( + private readonly roleName: string, + private readonly communityName: string, + private readonly communityId: string, + ) { + super(`seeds role "${roleName}" in "${communityName}"`); + } + + async performAs(actor: Actor): Promise { + const roleId = await seedEndUserRole({ connectionString: testMongoServer.getConnectionString(), dbName: mongoDbName }, { communityId: this.communityId, roleName: this.roleName }); + const roleIdsByCommunityName = await actor.answer(notes().get('roleIdsByCommunityName')).catch(() => ({}) as Record>); + await actor.attemptsTo( + notes().set('roleIdsByCommunityName', { + ...roleIdsByCommunityName, + [this.communityName]: { ...roleIdsByCommunityName[this.communityName], [this.roleName]: roleId }, + }), + ); + } +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/update-member-profile.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/update-member-profile.ts new file mode 100644 index 000000000..54bf14696 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/update-member-profile.ts @@ -0,0 +1,48 @@ +import { type Actor, notes, Task } from '@serenity-js/core'; +import { type MemberProfileUpdate, UpdateMemberProfile as UpdateMemberProfileAbility } from '../../../shared/abilities/update-member-profile.ts'; +import type { MemberNotes } from '../notes/member-notes.ts'; +import { PrincipalMemberIdForCommunity } from '../questions/principal-member-id-for-community.ts'; + +interface UpdateMemberProfileTaskDetails { + profile: MemberProfileUpdate; + memberId?: string; + communityId?: string; +} + +export class UpdateMember extends Task { + static with(details: UpdateMemberProfileTaskDetails) { + return new UpdateMember(details); + } + + private constructor(private readonly details: UpdateMemberProfileTaskDetails) { + super('updates a member profile'); + } + + async performAs(actor: Actor): Promise { + const memberId = this.details.memberId ?? (await actor.answer(notes().get('lastMemberId'))); + if (!memberId) { + throw new Error('Cannot update member profile because no member id is available in notes'); + } + + const communityId = this.details.communityId ?? (await actor.answer(notes().get('lastMemberCommunityId'))); + if (!communityId) { + throw new Error('Cannot update member profile because no community id is available in notes'); + } + + const principalMemberId = await actor.answer(PrincipalMemberIdForCommunity.inCommunity(communityId)); + const result = await UpdateMemberProfileAbility.as(actor).performAs(actor, { + memberId, + profile: this.details.profile, + communityId, + principalMemberId, + }); + + await actor.attemptsTo( + notes().set('lastMemberProfileEmail', result.profile?.email), + notes().set('lastExpectedMemberProfileEmail', this.details.profile.email), + notes().set('lastMemberStatus', 'SUCCESS'), + ); + } + + override toString = () => 'updates a member profile'; +} diff --git a/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/update-member-role.ts b/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/update-member-role.ts new file mode 100644 index 000000000..1c407aee5 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/contexts/community/tasks/update-member-role.ts @@ -0,0 +1,29 @@ +import { type Actor, notes, Task } from '@serenity-js/core'; +import { UpdateMemberRole as UpdateMemberRoleAbility } from '../../../shared/abilities/update-member-role.ts'; +import type { MemberNotes } from '../notes/member-notes.ts'; +import { PrincipalMemberIdForCommunity } from '../questions/principal-member-id-for-community.ts'; + +export class UpdateMemberRole extends Task { + static with(roleId: string, communityId: string): UpdateMemberRole { + return new UpdateMemberRole(roleId, communityId); + } + + private constructor( + private readonly roleId: string, + private readonly communityId: string, + ) { + super('updates a member role'); + } + + async performAs(actor: Actor): Promise { + const memberId = await actor.answer(notes().get('lastMemberId')); + const principalMemberId = await actor.answer(PrincipalMemberIdForCommunity.inCommunity(this.communityId)); + const roleName = await UpdateMemberRoleAbility.as(actor).performAs(actor, { + memberId, + roleId: this.roleId, + communityId: this.communityId, + principalMemberId, + }); + await actor.attemptsTo(notes().set('lastMemberRoleName', roleName)); + } +} diff --git a/packages/ocom-verification/acceptance-api/src/mock-application-services.ts b/packages/ocom-verification/acceptance-api/src/mock-application-services.ts index 3a2fedc8b..8bdc8a0f7 100644 --- a/packages/ocom-verification/acceptance-api/src/mock-application-services.ts +++ b/packages/ocom-verification/acceptance-api/src/mock-application-services.ts @@ -1,6 +1,7 @@ import type { BlobUploadAuthorizationHeader, BlobUploadCommonResponse, CreateBlobAuthorizationHeaderRequest } from '@cellix/service-blob-storage'; import { type ApplicationServicesFactory, buildApplicationServicesFactory } from '@ocom/application-services'; import type { ApiContextSpec } from '@ocom/context-spec'; +import { RegisterEventHandlers } from '@ocom/event-handler'; import { Persistence } from '@ocom/persistence'; import type { ServiceApolloServer } from '@ocom/service-apollo-server'; import type { BlobAddress, BlobStorageOperations, ClientUploadOperations, ListBlobsRequest, UploadTextBlobRequest } from '@ocom/service-blob-storage'; @@ -39,7 +40,7 @@ function createMockTokenValidation(): TokenValidation { openIdConfigKey: 'StaffPortal', }); } - const actor = actors.CommunityOwner; + const actor = Object.values(actors).find((candidate) => candidate.email === token) ?? actors.CommunityOwner; return Promise.resolve({ verifiedJwt: { given_name: actor.givenName, @@ -136,6 +137,7 @@ function createRecordingQueueStorageService(): QueueStorageOperations { export function createMockApplicationServicesFactory(serviceMongoose: ServiceMongoose): ApplicationServicesFactory { const dataSourcesFactory = Persistence(serviceMongoose); + RegisterEventHandlers(dataSourcesFactory.withSystemPassport().domainDataSource); const blobStorageService = createNoOpBlobStorageService(); const clientOperationsService = createNoOpClientOperationsService(); const queueStorageService = createRecordingQueueStorageService(); diff --git a/packages/ocom-verification/acceptance-api/src/servers/api-graphql-test-server.ts b/packages/ocom-verification/acceptance-api/src/servers/api-graphql-test-server.ts index 5c3ce3677..3b600d72c 100644 --- a/packages/ocom-verification/acceptance-api/src/servers/api-graphql-test-server.ts +++ b/packages/ocom-verification/acceptance-api/src/servers/api-graphql-test-server.ts @@ -1,5 +1,5 @@ import { ApolloGraphQLTestServer, type TestServer } from '@cellix/serenity-framework/servers'; -import type { ApplicationServices } from '@ocom/application-services'; +import type { ApplicationServices, PrincipalHints } from '@ocom/application-services'; import { combinedSchema } from '@ocom/graphql'; import depthLimit from 'graphql-depth-limit'; import { applyMiddleware } from 'graphql-middleware'; @@ -20,7 +20,12 @@ class ApiGraphQLTestServer implements TestServer { validationRules: [depthLimit(10)], context: async ({ req }) => { this.applicationServicesFactory ??= createMockApplicationServicesFactory(mongooseTestServer.getService()); - const applicationServices = await this.applicationServicesFactory.forRequest(req.headers.authorization ?? undefined); + const requestHints: PrincipalHints = { + memberId: Array.isArray(req.headers['x-member-id']) ? req.headers['x-member-id'][0] : req.headers['x-member-id'], + communityId: Array.isArray(req.headers['x-community-id']) ? req.headers['x-community-id'][0] : req.headers['x-community-id'], + }; + const hints = requestHints.memberId || requestHints.communityId ? requestHints : undefined; + const applicationServices = await this.applicationServicesFactory.forRequest(req.headers.authorization ?? undefined, hints); if (!applicationServices) { throw new Error('ApplicationServicesFactory required for test server'); } diff --git a/packages/ocom-verification/acceptance-api/src/shared/abilities/assign-member-account.ts b/packages/ocom-verification/acceptance-api/src/shared/abilities/assign-member-account.ts new file mode 100644 index 000000000..f7f95020b --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/shared/abilities/assign-member-account.ts @@ -0,0 +1,48 @@ +import { GraphQLClient } from '@cellix/serenity-framework/clients/graphql'; +import { Ability, type Actor } from '@serenity-js/core'; +import { MEMBER_CREATE_ACCOUNT_MUTATION } from '../graphql/member-operations.ts'; + +interface AssignMemberAccountDetails { + communityId: string; + principalMemberId: string; + memberId: string; + endUserId: string; +} + +type AssignMemberAccountHandler = (actor: Actor, details: AssignMemberAccountDetails) => Promise; + +type ExecuteWithRequestOptions = = Record>( + query: string, + variables?: Record, + options?: { headers?: Record }, +) => Promise<{ data: TData; errors?: Array<{ message?: string }> }>; + +export class AssignMemberAccount extends Ability { + constructor(private readonly handler: AssignMemberAccountHandler) { + super(); + } + + static using(handler: AssignMemberAccountHandler): AssignMemberAccount { + return new AssignMemberAccount(handler); + } + + async performAs(actor: Actor, details: AssignMemberAccountDetails): Promise { + await this.handler(actor, details); + } +} + +export function assignMemberAccountAbility(): AssignMemberAccount { + return AssignMemberAccount.using(async (actor, details) => { + const graphql = GraphQLClient.as(actor) as GraphQLClient & { execute: ExecuteWithRequestOptions }; + const response = await graphql.execute( + MEMBER_CREATE_ACCOUNT_MUTATION, + { input: { memberId: details.memberId, endUserId: details.endUserId } }, + { headers: { 'x-community-id': details.communityId, 'x-member-id': details.principalMemberId } }, + ); + const result = response.data?.['memberCreateAccount'] as Record | undefined; + const status = result?.['status'] as Record | undefined; + if (status?.['success'] !== true) { + throw new Error(String(status?.['errorMessage'] ?? 'Failed to assign member account')); + } + }); +} diff --git a/packages/ocom-verification/acceptance-api/src/shared/abilities/create-community.ts b/packages/ocom-verification/acceptance-api/src/shared/abilities/create-community.ts index 3881c69d1..2106eed6a 100644 --- a/packages/ocom-verification/acceptance-api/src/shared/abilities/create-community.ts +++ b/packages/ocom-verification/acceptance-api/src/shared/abilities/create-community.ts @@ -1,6 +1,6 @@ import { GraphQLClient } from '@cellix/serenity-framework/clients/graphql'; import { Ability, type Actor } from '@serenity-js/core'; -import { COMMUNITY_CREATE_MUTATION, GET_COMMUNITY_QUERY } from '../graphql/community-operations.ts'; +import { COMMUNITY_CREATE_MUTATION, CURRENT_END_USER_QUERY, GET_COMMUNITY_QUERY } from '../graphql/community-operations.ts'; /** Community details accepted by API verification flows. */ interface CreateCommunityDetails { @@ -36,6 +36,10 @@ export class CreateCommunity extends Ability { export function createCommunityAbility(): CreateCommunity { return CreateCommunity.using(async (actor, details) => { const graphql = GraphQLClient.as(actor); + const currentEndUserResponse = await graphql.execute(CURRENT_END_USER_QUERY); + if (!(currentEndUserResponse.data['currentEndUserAndCreateIfNotExists'] as Record | undefined)?.['id']) { + throw new Error('API did not establish the authenticated end user before community creation'); + } const response = await graphql.execute(COMMUNITY_CREATE_MUTATION, { input: { name: details.name }, }); diff --git a/packages/ocom-verification/acceptance-api/src/shared/abilities/index.ts b/packages/ocom-verification/acceptance-api/src/shared/abilities/index.ts index 41d8d8913..16b3413bd 100644 --- a/packages/ocom-verification/acceptance-api/src/shared/abilities/index.ts +++ b/packages/ocom-verification/acceptance-api/src/shared/abilities/index.ts @@ -2,4 +2,6 @@ export { assignStaffRoleAbility } from './assign-staff-role.ts'; export { createCommunityAbility } from './create-community.ts'; export { createStaffRoleAbility } from './create-staff-role.ts'; export { createGraphQLClientAbility } from './graphql-client.ts'; +export { removeMemberAbility } from './remove-member.ts'; +export { updateMemberProfileAbility } from './update-member-profile.ts'; export { updateStaffRoleAbility } from './update-staff-role.ts'; diff --git a/packages/ocom-verification/acceptance-api/src/shared/abilities/list-members.ts b/packages/ocom-verification/acceptance-api/src/shared/abilities/list-members.ts new file mode 100644 index 000000000..136e6d950 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/shared/abilities/list-members.ts @@ -0,0 +1,60 @@ +import { GraphQLClient } from '@cellix/serenity-framework/clients/graphql'; +import { Ability, type Actor } from '@serenity-js/core'; +import { MEMBERS_BY_COMMUNITY_QUERY } from '../graphql/member-operations.ts'; + +interface ListMembersDetails { + communityId: string; + principalMemberId: string; +} + +interface ListedMember { + memberName: string; +} + +type ListMembersHandler = (actor: Actor, details: ListMembersDetails) => Promise; + +export class ListMembers extends Ability { + constructor(private readonly handler: ListMembersHandler) { + super(); + } + + static using(handler: ListMembersHandler): ListMembers { + return new ListMembers(handler); + } + + async performAs(actor: Actor, details: ListMembersDetails): Promise { + return await this.handler(actor, details); + } +} + +export function listMembersAbility(): ListMembers { + return ListMembers.using(async (actor, details) => { + const graphql = GraphQLClient.as(actor); + const response = await graphql.execute( + MEMBERS_BY_COMMUNITY_QUERY, + { communityId: details.communityId }, + { + headers: { + 'x-community-id': details.communityId, + 'x-member-id': details.principalMemberId, + }, + }, + ); + + if (response.errors?.length) { + throw new Error( + response.errors + .map((error) => error.message) + .filter(Boolean) + .join('; ') || 'Failed to list members', + ); + } + + const members = response.data?.['membersByCommunityId']; + if (!Array.isArray(members)) { + throw new Error('API membersByCommunityId did not return a member list'); + } + + return members.map((member) => ({ memberName: String((member as Record)['memberName'] ?? '') })); + }); +} diff --git a/packages/ocom-verification/acceptance-api/src/shared/abilities/remove-member.ts b/packages/ocom-verification/acceptance-api/src/shared/abilities/remove-member.ts new file mode 100644 index 000000000..c77d5f113 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/shared/abilities/remove-member.ts @@ -0,0 +1,52 @@ +import { GraphQLClient } from '@cellix/serenity-framework/clients/graphql'; +import { Ability, type Actor } from '@serenity-js/core'; +import { REMOVE_MEMBER_MUTATION } from '../graphql/member-operations.ts'; + +interface RemoveMemberDetails { + memberId: string; + communityId: string; + principalMemberId: string; + authorizationToken?: string; +} + +type ExecuteWithRequestOptions = = Record>( + query: string, + variables?: Record, + options?: { headers?: Record }, +) => Promise<{ data: TData; errors?: Array<{ message?: string }> }>; + +export class RemoveMember extends Ability { + constructor(private readonly handler: (actor: Actor, details: RemoveMemberDetails) => Promise) { + super(); + } + + static using(handler: (actor: Actor, details: RemoveMemberDetails) => Promise): RemoveMember { + return new RemoveMember(handler); + } + + async performAs(actor: Actor, details: RemoveMemberDetails): Promise { + await this.handler(actor, details); + } +} + +export function removeMemberAbility(): RemoveMember { + return RemoveMember.using(async (actor, details) => { + const graphql = GraphQLClient.as(actor) as GraphQLClient & { execute: ExecuteWithRequestOptions }; + const response = await graphql.execute( + REMOVE_MEMBER_MUTATION, + { input: { memberId: details.memberId } }, + { + headers: { + 'x-community-id': details.communityId, + 'x-member-id': details.principalMemberId, + ...(details.authorizationToken ? { Authorization: `Bearer ${details.authorizationToken}` } : {}), + }, + }, + ); + const result = response.data?.['removeMember'] as Record | undefined; + const status = result?.['status'] as Record | undefined; + if (status?.['success'] !== true) { + throw new Error(String(status?.['errorMessage'] ?? response.errors?.map((error) => error.message).join('; ') ?? 'Failed to remove member')); + } + }); +} diff --git a/packages/ocom-verification/acceptance-api/src/shared/abilities/update-member-profile.ts b/packages/ocom-verification/acceptance-api/src/shared/abilities/update-member-profile.ts new file mode 100644 index 000000000..0943cc6e6 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/shared/abilities/update-member-profile.ts @@ -0,0 +1,121 @@ +import { GraphQLClient } from '@cellix/serenity-framework/clients/graphql'; +import { Ability, type Actor } from '@serenity-js/core'; +import { MEMBER_UPDATE_PROFILE_MUTATION } from '../graphql/member-operations.ts'; + +export interface MemberProfileUpdate { + name?: string; + email?: string; + bio?: string; + avatarDocumentId?: string; + interests?: string[]; + showInterests?: boolean; + showEmail?: boolean; + showProfile?: boolean; + showLocation?: boolean; + showProperties?: boolean; +} + +interface UpdateMemberProfileDetails { + memberId: string; + profile: MemberProfileUpdate; + communityId: string; + principalMemberId: string; +} + +interface UpdateMemberProfileResult { + id?: string; + profile?: MemberProfileUpdate; +} + +type UpdateMemberProfileHandler = (actor: Actor, details: UpdateMemberProfileDetails) => Promise; + +type ExecuteWithRequestOptions = = Record>( + query: string, + variables?: Record, + options?: { headers?: Record }, +) => Promise<{ data: TData; errors?: Array<{ message?: string }> }>; + +export class UpdateMemberProfile extends Ability { + constructor(private readonly handler: UpdateMemberProfileHandler) { + super(); + } + + static using(handler: UpdateMemberProfileHandler): UpdateMemberProfile { + return new UpdateMemberProfile(handler); + } + + async performAs(actor: Actor, details: UpdateMemberProfileDetails): Promise { + return await this.handler(actor, details); + } +} + +export function updateMemberProfileAbility(): UpdateMemberProfile { + return UpdateMemberProfile.using(async (actor, details) => { + const graphql = GraphQLClient.as(actor) as GraphQLClient & { execute: ExecuteWithRequestOptions }; + if (!details.communityId) { + throw new Error('communityId is required to update a member profile'); + } + if (!details.memberId) { + throw new Error('memberId is required to update a member profile'); + } + if (!details.profile || Object.keys(details.profile).length === 0) { + throw new Error('At least one profile field is required to update a member profile'); + } + if (!details.principalMemberId) { + throw new Error('principalMemberId is required to update a member profile'); + } + + const profileResponse = await graphql.execute( + MEMBER_UPDATE_PROFILE_MUTATION, + { + input: { + memberId: details.memberId, + profile: { + ...(details.profile.name !== undefined ? { name: details.profile.name } : {}), + ...(details.profile.email !== undefined ? { email: details.profile.email } : {}), + ...(details.profile.bio !== undefined ? { bio: details.profile.bio } : {}), + ...(details.profile.avatarDocumentId !== undefined ? { avatarDocumentId: details.profile.avatarDocumentId } : {}), + ...(details.profile.interests !== undefined ? { interests: details.profile.interests } : {}), + ...(details.profile.showInterests !== undefined ? { showInterests: details.profile.showInterests } : {}), + ...(details.profile.showEmail !== undefined ? { showEmail: details.profile.showEmail } : {}), + ...(details.profile.showProfile !== undefined ? { showProfile: details.profile.showProfile } : {}), + ...(details.profile.showLocation !== undefined ? { showLocation: details.profile.showLocation } : {}), + ...(details.profile.showProperties !== undefined ? { showProperties: details.profile.showProperties } : {}), + }, + }, + }, + { + headers: { + 'x-community-id': details.communityId, + 'x-member-id': details.principalMemberId, + }, + }, + ); + + const updateResult = profileResponse.data?.['memberUpdateProfile'] as Record | undefined; + const updateStatus = updateResult?.['status'] as Record | undefined; + if (updateStatus?.['success'] !== true) { + throw new Error(String(updateStatus?.['errorMessage'] ?? 'Failed to update member profile')); + } + + const updatedMember = updateResult?.['member'] as Record | undefined; + const profile = updatedMember?.['profile'] as Record | undefined; + const interests = Array.isArray(profile?.['interests']) ? (profile?.['interests'] as Array).map((value) => String(value)).filter((value) => value.length > 0) : undefined; + + return { + id: String(updatedMember?.['id'] ?? details.memberId), + profile: { + ...(profile?.['name'] !== undefined ? { name: String(profile['name'] ?? '') } : {}), + ...(profile?.['email'] !== undefined ? { email: String(profile['email'] ?? '') } : {}), + ...(profile?.['bio'] !== undefined ? { bio: String(profile['bio'] ?? '') } : {}), + ...(profile?.['avatarDocumentId'] !== undefined ? { avatarDocumentId: String(profile['avatarDocumentId'] ?? '') } : {}), + ...(interests !== undefined ? { interests } : {}), + ...(profile?.['showInterests'] !== undefined ? { showInterests: Boolean(profile['showInterests']) } : {}), + ...(profile?.['showEmail'] !== undefined ? { showEmail: Boolean(profile['showEmail']) } : {}), + ...(profile?.['showProfile'] !== undefined ? { showProfile: Boolean(profile['showProfile']) } : {}), + ...(profile?.['showLocation'] !== undefined ? { showLocation: Boolean(profile['showLocation']) } : {}), + ...(profile?.['showProperties'] !== undefined ? { showProperties: Boolean(profile['showProperties']) } : {}), + }, + }; + }); +} diff --git a/packages/ocom-verification/acceptance-api/src/shared/abilities/update-member-role.ts b/packages/ocom-verification/acceptance-api/src/shared/abilities/update-member-role.ts new file mode 100644 index 000000000..b31cf7a23 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/shared/abilities/update-member-role.ts @@ -0,0 +1,49 @@ +import { GraphQLClient } from '@cellix/serenity-framework/clients/graphql'; +import { Ability, type Actor } from '@serenity-js/core'; +import { MEMBER_ROLE_UPDATE_MUTATION } from '../graphql/member-operations.ts'; + +interface UpdateMemberRoleDetails { + memberId: string; + roleId: string; + communityId: string; + principalMemberId: string; +} + +type ExecuteWithRequestOptions = = Record>( + query: string, + variables?: Record, + options?: { headers?: Record }, +) => Promise<{ data: TData; errors?: Array<{ message?: string }> }>; + +export class UpdateMemberRole extends Ability { + constructor(private readonly handler: (actor: Actor, details: UpdateMemberRoleDetails) => Promise) { + super(); + } + + static using(handler: (actor: Actor, details: UpdateMemberRoleDetails) => Promise): UpdateMemberRole { + return new UpdateMemberRole(handler); + } + + async performAs(actor: Actor, details: UpdateMemberRoleDetails): Promise { + return await this.handler(actor, details); + } +} + +export function updateMemberRoleAbility(): UpdateMemberRole { + return UpdateMemberRole.using(async (actor, details) => { + const graphql = GraphQLClient.as(actor) as GraphQLClient & { execute: ExecuteWithRequestOptions }; + const response = await graphql.execute( + MEMBER_ROLE_UPDATE_MUTATION, + { input: { memberId: details.memberId, roleId: details.roleId, reason: 'Role assignment verification' } }, + { headers: { 'x-community-id': details.communityId, 'x-member-id': details.principalMemberId } }, + ); + const result = response.data?.['memberRoleUpdate'] as Record | undefined; + const status = result?.['status'] as Record | undefined; + if (status?.['success'] !== true) { + throw new Error(String(status?.['errorMessage'] ?? response.errors?.map((error) => error.message).join('; ') ?? 'Failed to update member role')); + } + const member = result?.['member'] as Record | undefined; + const role = member?.['role'] as Record | undefined; + return String(role?.['roleName'] ?? ''); + }); +} diff --git a/packages/ocom-verification/acceptance-api/src/shared/graphql/community-operations.ts b/packages/ocom-verification/acceptance-api/src/shared/graphql/community-operations.ts index f239508d5..b25cfb1c7 100644 --- a/packages/ocom-verification/acceptance-api/src/shared/graphql/community-operations.ts +++ b/packages/ocom-verification/acceptance-api/src/shared/graphql/community-operations.ts @@ -13,6 +13,14 @@ export const COMMUNITY_CREATE_MUTATION = ` } `; +export const CURRENT_END_USER_QUERY = ` + query CurrentEndUserAndCreateIfNotExists { + currentEndUserAndCreateIfNotExists { + id + } + } +`; + export const GET_COMMUNITY_QUERY = ` query CommunityById($id: ObjectID!) { communityById(id: $id) { diff --git a/packages/ocom-verification/acceptance-api/src/shared/graphql/member-operations.ts b/packages/ocom-verification/acceptance-api/src/shared/graphql/member-operations.ts new file mode 100644 index 000000000..403dbc64a --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/shared/graphql/member-operations.ts @@ -0,0 +1,141 @@ +export const MEMBER_CREATE_MUTATION = ` + mutation MemberCreate($input: MemberCreateInput!) { + memberCreate(input: $input) { + status { + success + errorMessage + } + member { + id + memberName + } + } + } +`; + +export const REMOVE_MEMBER_MUTATION = ` + mutation RemoveMember($input: RemoveMemberInput!) { + removeMember(input: $input) { + status { + success + errorMessage + } + } + } +`; + +export const MEMBER_ROLE_UPDATE_MUTATION = ` + mutation MemberRoleUpdate($input: UpdateMemberRoleInput!) { + memberRoleUpdate(input: $input) { + status { + success + errorMessage + } + member { + id + role { + id + roleName + } + } + } + } +`; + +export const MEMBER_UPDATE_PROFILE_MUTATION = ` + mutation MemberUpdateProfile($input: MemberUpdateProfileInput!) { + memberUpdateProfile(input: $input) { + status { + success + errorMessage + } + member { + id + profile { + name + email + bio + avatarDocumentId + interests + showInterests + showEmail + showProfile + showLocation + showProperties + } + } + } + } +`; + +export const MEMBER_CREATE_ACCOUNT_MUTATION = ` + mutation MemberCreateAccount($input: MemberCreateAccountInput!) { + memberCreateAccount(input: $input) { + status { + success + errorMessage + } + member { + id + } + } + } +`; + +export const END_USERS_BY_COMMUNITY_QUERY = ` + query EndUsersByCommunity($communityId: ObjectID!) { + endUsersByCommunityId(communityId: $communityId) { + id + displayName + } + } +`; + +export const MEMBERS_FOR_CURRENT_END_USER_QUERY = ` + query MembersForCurrentEndUser { + membersForCurrentEndUser { + id + community { + id + } + } + } +`; + +export const MEMBERS_BY_COMMUNITY_QUERY = ` + query MembersByCommunity($communityId: ObjectID!) { + membersByCommunityId(communityId: $communityId) { + id + memberName + } + } +`; + +export const MEMBER_BY_ID_QUERY = ` + query MemberById($id: ObjectID!) { + member(id: $id) { + id + memberName + community { + id + } + accounts { + user { + id + } + } + profile { + name + email + bio + avatarDocumentId + interests + showInterests + showEmail + showProfile + showLocation + showProperties + } + } + } +`; diff --git a/packages/ocom-verification/acceptance-api/src/shared/interactions/execute-graphql.ts b/packages/ocom-verification/acceptance-api/src/shared/interactions/execute-graphql.ts new file mode 100644 index 000000000..9d10151d1 --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/shared/interactions/execute-graphql.ts @@ -0,0 +1,15 @@ +import { GraphQLClient, type GraphQLExecuteOptions, type GraphQLResponse } from '@cellix/serenity-framework/clients/graphql'; +import { Interaction, TakeNotes } from '@serenity-js/core'; + +export interface GraphQLResponseNotes { + lastGraphQLResponse: GraphQLResponse; +} + +/** Executes a GraphQL operation and records its response for the current actor. */ +export const ExecuteGraphQL = { + operation: (query: string, variables?: Record, options?: GraphQLExecuteOptions) => + Interaction.where('#actor executes a GraphQL operation', async (actor) => { + const response = await GraphQLClient.as(actor).execute(query, variables, options); + TakeNotes.as(actor).notepad.set('lastGraphQLResponse', response); + }), +} as const; diff --git a/packages/ocom-verification/acceptance-api/src/shared/questions/last-graphql-response.ts b/packages/ocom-verification/acceptance-api/src/shared/questions/last-graphql-response.ts new file mode 100644 index 000000000..0b269bf6a --- /dev/null +++ b/packages/ocom-verification/acceptance-api/src/shared/questions/last-graphql-response.ts @@ -0,0 +1,21 @@ +import { notes, Question } from '@serenity-js/core'; +import type { GraphQLResponseNotes } from '../interactions/execute-graphql.ts'; + +/** Reads a field from the GraphQL response most recently recorded for the actor. */ +export const LastGraphQLResponse = { + field: (path: string) => + Question.about(`the "${path}" field of the last GraphQL response`, async (actor) => { + const response = await actor.answer(notes().get('lastGraphQLResponse')); + return getByPath(response.data, path) as TValue; + }), +} as const; + +function getByPath(value: unknown, path: string): unknown { + return path.split('.').reduce((current, segment) => { + if (!current || typeof current !== 'object') { + return undefined; + } + + return (current as Record)[segment]; + }, value); +} diff --git a/packages/ocom-verification/acceptance-api/src/world.ts b/packages/ocom-verification/acceptance-api/src/world.ts index f2a1db5e4..0c33b55e0 100644 --- a/packages/ocom-verification/acceptance-api/src/world.ts +++ b/packages/ocom-verification/acceptance-api/src/world.ts @@ -3,10 +3,15 @@ import type { ApiInfrastructureState } from '@cellix/serenity-framework/infrastr import { SerenityCast } from '@cellix/serenity-framework/serenity'; import { registerLifecycleHooks } from './cucumber-lifecycle-hooks.ts'; import { infrastructure } from './infrastructure.ts'; +import { assignMemberAccountAbility } from './shared/abilities/assign-member-account.ts'; import { assignStaffRoleAbility } from './shared/abilities/assign-staff-role.ts'; import { createCommunityAbility } from './shared/abilities/create-community.ts'; import { createStaffRoleAbility } from './shared/abilities/create-staff-role.ts'; import { createGraphQLClientAbility } from './shared/abilities/graphql-client.ts'; +import { listMembersAbility } from './shared/abilities/list-members.ts'; +import { removeMemberAbility } from './shared/abilities/remove-member.ts'; +import { updateMemberProfileAbility } from './shared/abilities/update-member-profile.ts'; +import { updateMemberRoleAbility } from './shared/abilities/update-member-role.ts'; import { updateStaffRoleAbility } from './shared/abilities/update-staff-role.ts'; export const CellixApiWorld = registerManagedSerenityWorld({ @@ -19,7 +24,21 @@ export const CellixApiWorld = registerManagedSerenityWorld({ createCast: (state) => new SerenityCast({ useNotepad: true, - abilities: [(actor) => createGraphQLClientAbility(graphqlUrl(state), actor.name), () => createCommunityAbility(), () => createStaffRoleAbility(), () => updateStaffRoleAbility(), () => assignStaffRoleAbility()], + abilities: [ + (actor) => createGraphQLClientAbility(graphqlUrl(state), actor.name), + () => createCommunityAbility(), + () => createStaffRoleAbility(), + () => updateStaffRoleAbility(), + () => assignStaffRoleAbility(), + () => listMembersAbility(), + () => assignMemberAccountAbility(), + () => updateMemberProfileAbility(), + () => removeMemberAbility(), + () => updateMemberRoleAbility(), + () => createStaffRoleAbility(), + () => updateStaffRoleAbility(), + () => assignStaffRoleAbility(), + ], }), }); diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/notes/member-notes.ts b/packages/ocom-verification/acceptance-ui/src/contexts/community/notes/member-notes.ts new file mode 100644 index 000000000..3a7fab4a4 --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/notes/member-notes.ts @@ -0,0 +1,28 @@ +export interface MemberUiNotes { + endUserIdsByLabel: Record; + membersByCommunityName: Record; + lastMemberId: string; + lastLinkedEndUserId: string; + memberCreated: boolean; + memberRemoved: boolean; + memberValidationError: string; + memberAccountLinked: boolean; + memberAccountCount: number; + memberAuthorizationError: string; + memberUpdated: boolean; + updatedMemberProfile: MemberProfileFormValues; + expectedMemberProfile: MemberProfileExpectation; +} + +export interface MemberProfileFormValues { + name: string; + email: string; + bio: string; + showInterests: boolean; + showEmail: boolean; + showProfile: boolean; + showLocation: boolean; + showProperties: boolean; +} + +export type MemberProfileExpectation = MemberProfileFormValues; diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-account-linked.ts b/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-account-linked.ts new file mode 100644 index 000000000..2dadf242a --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-account-linked.ts @@ -0,0 +1,11 @@ +import { notes, Question } from '@serenity-js/core'; +import type { MemberUiNotes } from '../notes/member-notes.ts'; + +export const MemberAccountLinked = (endUserId: string) => + Question.about('whether the member account was linked', async (actor) => { + const linked = await actor.answer(notes().get('memberAccountLinked')); + const linkedEndUserId = await actor.answer(notes().get('lastLinkedEndUserId')); + return linked && linkedEndUserId === endUserId; + }); + +export const MemberAccountCount = () => Question.about('the number of member account links', (actor) => actor.answer(notes().get('memberAccountCount'))); diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-created-flag.ts b/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-created-flag.ts new file mode 100644 index 000000000..f0f90091d --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-created-flag.ts @@ -0,0 +1,4 @@ +import { notes, Question } from '@serenity-js/core'; +import type { MemberUiNotes } from '../notes/member-notes.ts'; + +export const MemberCreatedFlag = () => Question.about('whether the member form was submitted', (actor) => actor.answer(notes().get('memberCreated'))); diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-listed-in-community.ts b/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-listed-in-community.ts new file mode 100644 index 000000000..ad94e0fc0 --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-listed-in-community.ts @@ -0,0 +1,10 @@ +import { RenderInDom } from '@cellix/serenity-framework/dom/render-in-dom'; +import { DomPageAdapter } from '@cellix/serenity-framework/pages/dom'; +import { MemberListPage } from '@ocom-verification/verification-shared/pages'; +import { Question } from '@serenity-js/core'; + +export const MemberListedInCommunity = (memberName: string) => + Question.about(`whether member "${memberName}" appears in the rendered member list`, async (actor) => { + const page = new MemberListPage(new DomPageAdapter(RenderInDom.as(actor).container)); + return await page.memberName(memberName).isVisible(); + }); diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-profile-updated.ts b/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-profile-updated.ts new file mode 100644 index 000000000..033809a80 --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-profile-updated.ts @@ -0,0 +1,6 @@ +import { notes, Question } from '@serenity-js/core'; +import type { MemberProfileFormValues, MemberUiNotes } from '../notes/member-notes.ts'; + +export const UpdatedMemberProfile = () => Question.about('the submitted member profile', (actor) => actor.answer(notes().get('updatedMemberProfile')) as Promise); + +export const MemberUpdatedFlag = () => Question.about('whether the member profile was updated', (actor) => actor.answer(notes().get('memberUpdated'))); diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-removed-flag.ts b/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-removed-flag.ts new file mode 100644 index 000000000..d451cd9f4 --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-removed-flag.ts @@ -0,0 +1,4 @@ +import { notes, Question } from '@serenity-js/core'; +import type { MemberUiNotes } from '../notes/member-notes.ts'; + +export const MemberRemovedFlag = () => Question.about('whether the member was removed', (actor) => actor.answer(notes().get('memberRemoved'))); diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/assign-member-account.steps.tsx b/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/assign-member-account.steps.tsx new file mode 100644 index 000000000..c4f6008b2 --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/assign-member-account.steps.tsx @@ -0,0 +1,91 @@ +import { Render } from '@cellix/serenity-framework/dom/render-in-dom'; +import { Given, Then, When } from '@cucumber/cucumber'; +import { actors, END_USER_IDS } from '@ocom-verification/verification-shared/test-data'; +import { actorCalled, actorInTheSpotlight, notes } from '@serenity-js/core'; +import React from 'react'; +import { MembersAccountsAdd } from '../../../../../../ocom/ui-community-route-admin/src/components/members-accounts-add.tsx'; +import type { AdminMembersAccountsAddContainerEndUserFieldsFragment, MemberCreateAccountInput } from '../../../../../../ocom/ui-community-route-admin/src/generated.tsx'; +import { wrapOcomComponent } from '../../../shared/ocom-component-wrapper.ts'; +import type { MemberUiNotes } from '../notes/member-notes.ts'; +import { MemberAccountCount, MemberAccountLinked } from '../questions/member-account-linked.ts'; +import { AssignMemberAccount } from '../tasks/assign-member-account.ts'; + +const reactGlobal = globalThis as typeof globalThis & { React?: typeof React }; +reactGlobal.React ??= React; + +const accountDetails: Record = { + Charlie: { + id: END_USER_IDS.communityOwner, + displayName: `${actors.CommunityOwner.givenName} ${actors.CommunityOwner.familyName}`, + email: actors.CommunityOwner.email, + }, +}; + +Given('end-user account {string} is available for assignment in {string}', async (accountLabel: string, _communityName: string) => { + const actor = actorInTheSpotlight(); + const account = accountDetails[accountLabel]; + if (!account) { + throw new Error(`Unknown end-user account label "${accountLabel}"`); + } + const memberId = await actor.answer(notes().get('lastMemberId')); + const endUser: AdminMembersAccountsAddContainerEndUserFieldsFragment = { + id: account.id, + displayName: account.displayName, + personalInformation: { contactInformation: { email: account.email } }, + }; + const onSave = async (values: MemberCreateAccountInput): Promise => { + const accountCount = await actor.answer(notes().get('memberAccountCount')).catch(() => 0); + if (accountCount > 0) { + await actor.attemptsTo(notes().set('memberValidationError', 'Selected user is already associated with this member')); + return; + } + await actor.attemptsTo( + notes().set('memberAccountLinked', values.memberId === memberId && values.endUserId === account.id), + notes().set('lastLinkedEndUserId', String(values.endUserId)), + notes().set('memberAccountCount', accountCount + 1), + notes().set('memberValidationError', ''), + ); + }; + await actor.attemptsTo( + notes().set('endUserIdsByLabel', { [accountLabel]: account.id }), + notes().set('memberAccountLinked', false), + notes().set('memberAccountCount', 0), + notes().set('lastLinkedEndUserId', ''), + Render.component( + , + { wrapper: wrapOcomComponent() }, + ), + ); +}); + +When('{word} associates end-user account {string} to member {string} in {string}', async (actorName: string, accountLabel: string, _memberName: string, _communityName: string) => { + const account = accountDetails[accountLabel]; + if (!account) { + throw new Error(`Unknown end-user account label "${accountLabel}"`); + } + await actorCalled(actorName).attemptsTo(notes().set('memberValidationError', ''), AssignMemberAccount()); +}); + +Given('member {string} is already linked to end-user account {string}', async (_memberName: string, _accountLabel: string) => { + await actorInTheSpotlight().attemptsTo(AssignMemberAccount()); +}); + +Then('member {string} should be linked to end-user account {string}', async (_memberName: string, accountLabel: string) => { + const actor = actorInTheSpotlight(); + const endUserIds = await actor.answer(notes().get('endUserIdsByLabel')); + if (!(await actor.answer(MemberAccountLinked(endUserIds[accountLabel] ?? '')))) { + throw new Error(`Expected the member to be linked to end-user account "${accountLabel}"`); + } +}); + +Then('member {string} should remain linked to end-user account {string} only once', async (_memberName: string, _accountLabel: string) => { + const count = await actorInTheSpotlight().answer(MemberAccountCount()); + if (count !== 1) { + throw new Error(`Expected one member account association but found ${count}`); + } +}); diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/create-member.steps.tsx b/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/create-member.steps.tsx new file mode 100644 index 000000000..6a049401a --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/create-member.steps.tsx @@ -0,0 +1,117 @@ +import { GherkinDataTable } from '@cellix/serenity-framework/cucumber/gherkin-data-table'; +import { Render, RenderInDom } from '@cellix/serenity-framework/dom/render-in-dom'; +import { DomPageAdapter } from '@cellix/serenity-framework/pages/dom'; +import { type DataTable, Given, Then, When } from '@cucumber/cucumber'; +import { MemberCreatePage } from '@ocom-verification/verification-shared/pages'; +import { actorCalled, actorInTheSpotlight, notes } from '@serenity-js/core'; +import React from 'react'; +import { MembersCreate } from '../../../../../../ocom/ui-community-route-admin/src/components/members-create.tsx'; +import { MemberProfile } from '../../../../../../ocom/ui-community-shared/src/components/member-profile.tsx'; +import type { SharedMemberProfileContainerMemberFieldsFragment } from '../../../../../../ocom/ui-community-shared/src/generated.tsx'; +import { wrapOcomComponent } from '../../../shared/ocom-component-wrapper.ts'; +import type { AcceptanceUiMemberCreatePage } from '../../../shared/page-contracts.ts'; +import type { MemberProfileFormValues, MemberUiNotes } from '../notes/member-notes.ts'; +import { MemberCreatedFlag } from '../questions/member-created-flag.ts'; +import { CreateMember } from '../tasks/create-member.ts'; + +const reactGlobal = globalThis as typeof globalThis & { React?: typeof React }; +reactGlobal.React ??= React; + +interface MemberDetails { + memberName?: string; +} + +Given('{word} is signed in as a community owner for member management', async (actorName: string) => { + const actor = actorCalled(actorName); + + const onSave = async (): Promise => { + await actor.attemptsTo(notes().set('memberCreated', true)); + }; + + await actor.attemptsTo(notes().set('memberCreated', false), Render.component(, { wrapper: wrapOcomComponent() })); +}); + +Given('{word} has a community named {string}', (_actorName: string, _communityName: string) => undefined); + +When('{word} creates a member in {string} with:', async (actorName: string, communityName: string, dataTable: DataTable) => { + const actor = actorCalled(actorName); + const details = GherkinDataTable.from(dataTable).rowsHash(); + const memberName = details.memberName?.trim() ?? ''; + + if (!memberName) { + throw new Error('memberName is required'); + } + + await actor.attemptsTo(CreateMember(memberName)); + await actor.attemptsTo(notes().set('lastMemberId', 'member-charlie-walker')); + const membersByCommunityName = await actor.answer(notes().get('membersByCommunityName')).catch(() => ({})); + await actor.attemptsTo( + notes().set('membersByCommunityName', { + ...membersByCommunityName, + [communityName]: [...(membersByCommunityName[communityName] ?? []), memberName], + }), + ); + + const onProfileSave = async (profile: MemberProfileFormValues): Promise => { + await actor.attemptsTo(notes().set('memberUpdated', true), notes().set('updatedMemberProfile', profile)); + return true; + }; + const profileData: SharedMemberProfileContainerMemberFieldsFragment = { + id: 'member-charlie-walker', + memberName, + profile: { + name: '', + email: '', + bio: '', + showInterests: false, + showEmail: false, + showProfile: false, + showLocation: false, + showProperties: false, + }, + createdAt: new Date(), + updatedAt: new Date(), + }; + + await actor.attemptsTo( + notes().set('memberUpdated', false), + Render.component( + , + { wrapper: wrapOcomComponent() }, + ), + ); +}); + +Then('the member should be created successfully in {string}', async (_communityName: string) => { + const submitted = await actorInTheSpotlight().answer(MemberCreatedFlag()); + if (!submitted) { + throw new Error('Expected member form to be submitted'); + } +}); + +When('{word} attempts to create a member in {string} with:', async (actorName: string, _communityName: string, dataTable: DataTable) => { + const actor = actorCalled(actorName); + const details = GherkinDataTable.from(dataTable).rowsHash(); + await actor.attemptsTo(notes().set('memberCreated', false), notes().set('memberValidationError', ''), CreateMember(details.memberName?.trim() ?? '')); + const page: AcceptanceUiMemberCreatePage = new MemberCreatePage(new DomPageAdapter(RenderInDom.as(actor).container)); + await actor.attemptsTo(notes().set('memberValidationError', (await page.validationError.textContent()) ?? '')); +}); + +Then('she should see a member error for {string}', async (fieldName: string) => { + const error = await actorInTheSpotlight().answer(notes().get('memberValidationError')); + const isFieldMentioned = error.toLowerCase().includes(fieldName.toLowerCase()); + if (!error || (!isFieldMentioned && !/cannot be empty|required|missing|invalid|must not be empty|please input|already associated/i.test(error))) { + throw new Error(`Expected a validation error related to "${fieldName}", but got: "${error}"`); + } +}); + +Then('no new member should be created in {string}', async (_communityName: string) => { + if (await actorInTheSpotlight().answer(MemberCreatedFlag())) { + throw new Error('Expected no member to be created, but the form was submitted'); + } +}); diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/index.ts b/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/index.ts index bc657d814..4d3489e7d 100644 --- a/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/index.ts +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/index.ts @@ -1,2 +1,7 @@ // Community context step definitions import './create-community.steps.tsx'; +import './create-member.steps.tsx'; +import './list-members.steps.tsx'; +import './remove-member.steps.tsx'; +import './assign-member-account.steps.tsx'; +import './update-member.steps.tsx'; diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/list-members.steps.tsx b/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/list-members.steps.tsx new file mode 100644 index 000000000..341bfa0ce --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/list-members.steps.tsx @@ -0,0 +1,61 @@ +import { type DataTable, Given, Then, When } from '@cucumber/cucumber'; +import { actorCalled, actorInTheSpotlight, notes } from '@serenity-js/core'; +import type { MemberUiNotes } from '../notes/member-notes.ts'; +import { MemberListedInCommunity } from '../questions/member-listed-in-community.ts'; +import { ListMembers } from '../tasks/list-members.tsx'; +import { SearchMemberList } from '../tasks/search-member-list.ts'; + +interface ListedMemberDetails { + memberName: string; + role?: string; +} + +Given('{word} is an authenticated community admin for {string}', async (actorName: string, _communityName: string) => { + const owner = actorInTheSpotlight(); + const membersByCommunityName = await owner.answer(notes().get('membersByCommunityName')).catch(() => ({})); + await actorCalled(actorName).attemptsTo(notes().set('membersByCommunityName', membersByCommunityName)); +}); + +Given('the following members exist in {string}:', async (communityName: string, dataTable: DataTable) => { + const actor = actorInTheSpotlight(); + const membersByCommunityName = await actor.answer(notes().get('membersByCommunityName')).catch(() => ({})); + await actor.attemptsTo( + notes().set('membersByCommunityName', { + ...membersByCommunityName, + [communityName]: (dataTable.hashes() as ListedMemberDetails[]).map(({ memberName }) => memberName.trim()), + }), + ); +}); + +When('{word} lists members for {string}', async (actorName: string, communityName: string) => { + const actor = actorCalled(actorName); + const membersByCommunityName = await actor.answer(notes().get('membersByCommunityName')); + await actor.attemptsTo(ListMembers(membersByCommunityName[communityName] ?? [])); +}); + +When('{word} searches the member list in {string} for {string}', async (actorName: string, communityName: string, searchTerm: string) => { + const actor = actorCalled(actorName); + const membersByCommunityName = await actor.answer(notes().get('membersByCommunityName')); + await actor.attemptsTo(ListMembers(membersByCommunityName[communityName] ?? []), SearchMemberList(searchTerm)); +}); + +Then('{word} should see the following members in {string}:', async (actorName: string, _communityName: string, dataTable: DataTable) => { + const actor = actorCalled(actorName); + for (const { memberName } of dataTable.hashes() as ListedMemberDetails[]) { + if (!(await actor.answer(MemberListedInCommunity(memberName)))) { + throw new Error(`Expected member "${memberName}" to appear in the rendered member list`); + } + } +}); + +Then('{word} should not see member {string} from {string}', async (actorName: string, memberName: string, _communityName: string) => { + if (await actorCalled(actorName).answer(MemberListedInCommunity(memberName))) { + throw new Error(`Expected member "${memberName}" not to appear in the rendered member list`); + } +}); + +Then('{word} should not see member {string} in the filtered results', async (actorName: string, memberName: string) => { + if (await actorCalled(actorName).answer(MemberListedInCommunity(memberName))) { + throw new Error(`Expected member "${memberName}" not to appear in the filtered member list`); + } +}); diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/remove-member.steps.tsx b/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/remove-member.steps.tsx new file mode 100644 index 000000000..8d72b1cc0 --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/remove-member.steps.tsx @@ -0,0 +1,112 @@ +import { Render } from '@cellix/serenity-framework/dom/render-in-dom'; +import { Given, Then, When } from '@cucumber/cucumber'; +import { actorCalled, actorInTheSpotlight, notes } from '@serenity-js/core'; +import { MemberList } from '../../../../../../ocom/ui-community-route-admin/src/components/members-list.tsx'; +import type { AdminMemberListContainerMemberFieldsFragment } from '../../../../../../ocom/ui-community-route-admin/src/generated.tsx'; +import { wrapOcomComponent } from '../../../shared/ocom-component-wrapper.ts'; +import type { MemberUiNotes } from '../notes/member-notes.ts'; +import { MemberListedInCommunity } from '../questions/member-listed-in-community.ts'; +import { MemberRemovedFlag } from '../questions/member-removed-flag.ts'; +import { RemoveMember } from '../tasks/remove-member.ts'; + +Given('{word} is signed in without membership in {string}', async (actorName: string, _communityName: string) => { + const owner = actorInTheSpotlight(); + const memberId = await owner.answer(notes().get('lastMemberId')); + const actor = actorCalled(actorName); + const member: AdminMemberListContainerMemberFieldsFragment = { + id: memberId, + memberName: 'Charlie Walker', + isAdmin: false, + accounts: [], + profile: null, + createdAt: new Date(), + updatedAt: new Date(), + }; + const onRemoveMember = async (): Promise => { + await actor.attemptsTo(notes().set('memberAuthorizationError', 'You do not have permission to remove this member'), notes().set('memberRemoved', false)); + return false; + }; + await actor.attemptsTo( + notes().set('lastMemberId', memberId), + notes().set('memberRemoved', false), + notes().set('memberAuthorizationError', ''), + Render.component( + , + { wrapper: wrapOcomComponent() }, + ), + ); +}); + +When('{word} removes member {string} from {string}', async (actorName: string, memberName: string, _communityName: string) => { + const actor = actorCalled(actorName); + const memberId = await actor.answer(notes().get('lastMemberId')); + const member: AdminMemberListContainerMemberFieldsFragment = { + id: memberId, + memberName, + isAdmin: false, + accounts: [], + profile: null, + createdAt: new Date(), + updatedAt: new Date(), + }; + const onRemoveMember = async (removedMemberId: string): Promise => { + await actor.attemptsTo(notes().set('memberRemoved', removedMemberId === memberId)); + return removedMemberId === memberId; + }; + + await actor.attemptsTo( + notes().set('memberRemoved', false), + Render.component( + , + { wrapper: wrapOcomComponent() }, + ), + RemoveMember(memberName), + ); + + if (await actor.answer(MemberRemovedFlag())) { + await actor.attemptsTo( + Render.component( + , + { wrapper: wrapOcomComponent() }, + ), + ); + } +}); + +Then('the member should be removed successfully from {string}', async (_communityName: string) => { + if (!(await actorInTheSpotlight().answer(MemberRemovedFlag()))) { + throw new Error('Expected member removal callback to succeed'); + } +}); + +Then('member {string} should not appear in member listings for {string}', async (memberName: string, _communityName: string) => { + if (await actorInTheSpotlight().answer(MemberListedInCommunity(memberName))) { + throw new Error(`Expected member "${memberName}" not to appear in the rendered member list`); + } +}); + +When('{word} attempts to remove member {string} from {string}', async (actorName: string, memberName: string, _communityName: string) => { + await actorCalled(actorName).attemptsTo(RemoveMember(memberName)); +}); + +Then('{word} should receive an authorization error for member management', async (actorName: string) => { + const error = await actorCalled(actorName).answer(notes().get('memberAuthorizationError')); + if (!/permission|unauthorized|forbidden/i.test(error)) { + throw new Error(`Expected a member-management authorization error, but got: "${error}"`); + } +}); + +Then('member {string} should remain in {string}', async (memberName: string, _communityName: string) => { + if (!(await actorInTheSpotlight().answer(MemberListedInCommunity(memberName)))) { + throw new Error(`Expected member "${memberName}" to remain in the rendered member list`); + } +}); diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/update-member.steps.tsx b/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/update-member.steps.tsx new file mode 100644 index 000000000..d53833ce2 --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/update-member.steps.tsx @@ -0,0 +1,62 @@ +import { GherkinDataTable } from '@cellix/serenity-framework/cucumber/gherkin-data-table'; +import { type DataTable, Then, When } from '@cucumber/cucumber'; +import { actorCalled, actorInTheSpotlight, notes } from '@serenity-js/core'; +import type { MemberProfileExpectation, MemberProfileFormValues, MemberUiNotes } from '../notes/member-notes.ts'; +import { MemberUpdatedFlag, UpdatedMemberProfile } from '../questions/member-profile-updated.ts'; +import { UpdateMemberProfile } from '../tasks/update-member-profile.ts'; + +interface MemberProfileUpdateDetails { + name?: string; + email?: string; + bio?: string; + avatarDocumentId?: string; + interests?: string; + showInterests?: string; + showEmail?: string; + showProfile?: string; + showLocation?: string; + showProperties?: string; +} + +When('{word} updates member {string} in {string} with:', async (actorName: string, _memberName: string, _communityName: string, dataTable: DataTable) => { + const actor = actorCalled(actorName); + const profile = toMemberProfileExpectation(GherkinDataTable.from(dataTable).rowsHash()); + + await actor.attemptsTo(notes().set('memberUpdated', false), notes().set('expectedMemberProfile', profile), UpdateMemberProfile(profile)); +}); + +Then('the member should be updated successfully in {string}', async (_communityName: string) => { + const actor = actorInTheSpotlight(); + const updated = await actor.answer(MemberUpdatedFlag()); + if (!updated) { + throw new Error('Expected member profile form to be submitted'); + } + + assertProfileMatches(await actor.answer(notes().get('expectedMemberProfile')), await actor.answer(UpdatedMemberProfile())); +}); + +function toMemberProfileExpectation(details: MemberProfileUpdateDetails): MemberProfileExpectation { + return { + name: details.name ?? '', + email: details.email ?? '', + bio: details.bio ?? '', + showInterests: toBoolean(details.showInterests), + showEmail: toBoolean(details.showEmail), + showProfile: toBoolean(details.showProfile), + showLocation: toBoolean(details.showLocation), + showProperties: toBoolean(details.showProperties), + }; +} + +function toBoolean(value: string | undefined): boolean { + return value?.trim().toLowerCase() === 'true'; +} + +function assertProfileMatches(expected: MemberProfileExpectation, actual: MemberProfileFormValues): void { + for (const [field, expectedValue] of Object.entries(expected)) { + const actualValue = actual[field as keyof MemberProfileFormValues]; + if (JSON.stringify(actualValue) !== JSON.stringify(expectedValue)) { + throw new Error(`Expected profile ${field} to be ${JSON.stringify(expectedValue)}, but got ${JSON.stringify(actualValue)}`); + } + } +} diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/assign-member-account.ts b/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/assign-member-account.ts new file mode 100644 index 000000000..e96e237a8 --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/assign-member-account.ts @@ -0,0 +1,20 @@ +import { DomPageAdapter } from '@cellix/serenity-framework/pages/dom'; +import { TaskStep } from '@cellix/serenity-framework/serenity'; +import { MemberAccountsPage } from '@ocom-verification/verification-shared/pages'; +import { type Actor, Task } from '@serenity-js/core'; +import type { AcceptanceUiMemberAccountsPage } from '../../../shared/page-contracts.ts'; + +async function flushPendingReactWork(): Promise { + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); +} + +export const AssignMemberAccount = (): Task => + Task.where( + '#actor assigns the selected end-user account to a member', + new TaskStep('#actor adds the selected member account', async () => { + const page: AcceptanceUiMemberAccountsPage = new MemberAccountsPage(new DomPageAdapter(document.body)); + await page.clickAddMemberAccount(); + await flushPendingReactWork(); + }), + ); diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/create-member.ts b/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/create-member.ts new file mode 100644 index 000000000..13105c850 --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/create-member.ts @@ -0,0 +1,25 @@ +import { RenderInDom } from '@cellix/serenity-framework/dom/render-in-dom'; +import { DomPageAdapter } from '@cellix/serenity-framework/pages/dom'; +import { TaskStep } from '@cellix/serenity-framework/serenity'; +import { MemberCreatePage } from '@ocom-verification/verification-shared/pages'; +import { type Actor, Task } from '@serenity-js/core'; +import type { AcceptanceUiMemberCreatePage } from '../../../shared/page-contracts.ts'; + +/** Let the form's async `onFinish` callback settle before assertions run. */ +async function flushPendingReactWork(): Promise { + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); +} + +export const CreateMember = (memberName: string): Task => + Task.where( + `#actor creates a member named "${memberName}"`, + new TaskStep(`#actor fills the member name "${memberName}" and submits`, async (actor) => { + const page: AcceptanceUiMemberCreatePage = new MemberCreatePage(new DomPageAdapter(RenderInDom.as(actor).container)); + + await page.fillMemberName(memberName); + await page.clickCreateMember(); + + await flushPendingReactWork(); + }), + ); diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/list-members.tsx b/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/list-members.tsx new file mode 100644 index 000000000..e4a76d2ca --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/list-members.tsx @@ -0,0 +1,18 @@ +import { Render } from '@cellix/serenity-framework/dom/render-in-dom'; +import { MemberList } from '../../../../../../ocom/ui-community-route-admin/src/components/members-list.tsx'; +import type { AdminMemberListContainerMemberFieldsFragment } from '../../../../../../ocom/ui-community-route-admin/src/generated.tsx'; +import { wrapOcomComponent } from '../../../shared/ocom-component-wrapper.ts'; + +export const ListMembers = (memberNames: string[]) => { + const members: AdminMemberListContainerMemberFieldsFragment[] = memberNames.map((memberName, index) => ({ + id: `member-${index}-${memberName.toLowerCase().replaceAll(' ', '-')}`, + memberName, + isAdmin: false, + accounts: [], + profile: null, + createdAt: new Date(), + updatedAt: new Date(), + })); + + return Render.component(, { wrapper: wrapOcomComponent() }); +}; diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/remove-member.ts b/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/remove-member.ts new file mode 100644 index 000000000..ffe7bd493 --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/remove-member.ts @@ -0,0 +1,16 @@ +import { RenderInDom } from '@cellix/serenity-framework/dom/render-in-dom'; +import { DomPageAdapter } from '@cellix/serenity-framework/pages/dom'; +import { TaskStep } from '@cellix/serenity-framework/serenity'; +import { MemberListPage } from '@ocom-verification/verification-shared/pages'; +import { type Actor, Task } from '@serenity-js/core'; +import type { AcceptanceUiMemberListPage } from '../../../shared/page-contracts.ts'; + +export const RemoveMember = (memberName: string): Task => + Task.where( + '#actor removes the member', + new TaskStep('#actor clicks Remove for the member', async (actor) => { + const page: AcceptanceUiMemberListPage = new MemberListPage(new DomPageAdapter(RenderInDom.as(actor).container)); + await page.clickRemoveMember(memberName); + await new Promise((resolve) => setTimeout(resolve, 0)); + }), + ); diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/search-member-list.ts b/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/search-member-list.ts new file mode 100644 index 000000000..3698c06fd --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/search-member-list.ts @@ -0,0 +1,15 @@ +import { RenderInDom } from '@cellix/serenity-framework/dom/render-in-dom'; +import { DomPageAdapter } from '@cellix/serenity-framework/pages/dom'; +import { TaskStep } from '@cellix/serenity-framework/serenity'; +import { MemberListPage } from '@ocom-verification/verification-shared/pages'; +import { type Actor, Task } from '@serenity-js/core'; +import type { AcceptanceUiMemberListPage } from '../../../shared/page-contracts.ts'; + +export const SearchMemberList = (searchTerm: string): Task => + Task.where( + `#actor searches the member list for "${searchTerm}"`, + new TaskStep(`#actor enters "${searchTerm}" in the member search`, async (actor) => { + const page: AcceptanceUiMemberListPage = new MemberListPage(new DomPageAdapter(RenderInDom.as(actor).container)); + await page.searchByMemberName(searchTerm); + }), + ); diff --git a/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/update-member-profile.ts b/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/update-member-profile.ts new file mode 100644 index 000000000..30ebaab40 --- /dev/null +++ b/packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/update-member-profile.ts @@ -0,0 +1,33 @@ +import { RenderInDom } from '@cellix/serenity-framework/dom/render-in-dom'; +import { DomPageAdapter } from '@cellix/serenity-framework/pages/dom'; +import { TaskStep } from '@cellix/serenity-framework/serenity'; +import { MemberProfilePage } from '@ocom-verification/verification-shared/pages'; +import { type Actor, Task } from '@serenity-js/core'; +import type { AcceptanceUiMemberProfilePage } from '../../../shared/page-contracts.ts'; +import type { MemberProfileFormValues } from '../notes/member-notes.ts'; + +async function flushPendingReactWork(): Promise { + await new Promise((resolve) => setTimeout(resolve, 0)); + await new Promise((resolve) => setTimeout(resolve, 0)); +} + +export const UpdateMemberProfile = (profile: MemberProfileFormValues): Task => + Task.where( + '#actor updates the member profile', + new TaskStep('#actor edits and saves the member profile', async (actor) => { + const page: AcceptanceUiMemberProfilePage = new MemberProfilePage(new DomPageAdapter(RenderInDom.as(actor).container)); + + await page.clickEditProfile(); + await page.fillDisplayName(profile.name); + await page.fillEmail(profile.email); + await page.fillBio(profile.bio); + await page.setShowInterests(profile.showInterests); + await page.setShowEmail(profile.showEmail); + await page.setShowProfile(profile.showProfile); + await page.setShowLocation(profile.showLocation); + await page.setShowProperties(profile.showProperties); + await page.clickSaveProfile(); + + await flushPendingReactWork(); + }), + ); diff --git a/packages/ocom-verification/acceptance-ui/src/shared/page-contracts.ts b/packages/ocom-verification/acceptance-ui/src/shared/page-contracts.ts index b7512789f..732ec8c44 100644 --- a/packages/ocom-verification/acceptance-ui/src/shared/page-contracts.ts +++ b/packages/ocom-verification/acceptance-ui/src/shared/page-contracts.ts @@ -1,5 +1,16 @@ -import type { CommunityPage, HomePage } from '@ocom-verification/verification-shared/pages'; +import type { CommunityPage, HomePage, MemberAccountsPage, MemberCreatePage, MemberListPage, MemberProfilePage } from '@ocom-verification/verification-shared/pages'; export type AcceptanceUiHomePage = Pick; export type AcceptanceUiCommunityPage = Pick; + +export type AcceptanceUiMemberCreatePage = Pick; + +export type AcceptanceUiMemberListPage = Pick; + +export type AcceptanceUiMemberAccountsPage = Pick; + +export type AcceptanceUiMemberProfilePage = Pick< + MemberProfilePage, + 'clickEditProfile' | 'clickSaveProfile' | 'fillDisplayName' | 'fillEmail' | 'fillBio' | 'setShowInterests' | 'setShowEmail' | 'setShowProfile' | 'setShowLocation' | 'setShowProperties' +>; diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/abilities/community-portal-page.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/abilities/community-portal-page.ts new file mode 100644 index 000000000..6bde74596 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/abilities/community-portal-page.ts @@ -0,0 +1,55 @@ +import { PlaywrightPageAdapter } from '@cellix/serenity-framework/pages/playwright'; +import { BrowseTheWeb } from '@cellix/serenity-framework/serenity/browser'; +import { MemberAccountsPage, MemberCreatePage, MemberListPage, MemberProfilePage } from '@ocom-verification/verification-shared/pages'; +import type { Actor } from '@serenity-js/core'; +import type { Page } from 'playwright'; + +export const communityPortalPageOf = (actor: Actor): Page => BrowseTheWeb.withActor(actor).page; + +export const memberCreatePageOn = (page: Page): MemberCreatePage => new MemberCreatePage(new PlaywrightPageAdapter(page)); + +export const memberListPageOn = (page: Page): MemberListPage => new MemberListPage(new PlaywrightPageAdapter(page)); + +export const memberProfilePageOn = (page: Page): MemberProfilePage => new MemberProfilePage(new PlaywrightPageAdapter(page)); + +export const memberAccountsPageOn = (page: Page): MemberAccountsPage => new MemberAccountsPage(new PlaywrightPageAdapter(page)); + +/** Navigate to a community member list and wait for its search control to render. */ +export const openMemberListFor = async (page: Page, communityId: string, routeMemberId: string): Promise => { + await page.goto(`/community/${encodeURIComponent(communityId)}/admin/${encodeURIComponent(routeMemberId)}/members`, { waitUntil: 'networkidle' }); + const memberListPage = memberListPageOn(page); + await memberListPage.searchInput.waitFor({ state: 'visible', timeout: 15_000 }); + return memberListPage; +}; + +/** Navigate to a community member create form and wait for its name input. */ +export const openMemberCreateFormFor = async (page: Page, communityId: string, routeMemberId: string): Promise => { + await page.goto(`/community/${encodeURIComponent(communityId)}/admin/${encodeURIComponent(routeMemberId)}/members/create`, { waitUntil: 'networkidle' }); + const memberCreatePage = memberCreatePageOn(page); + await memberCreatePage.memberNameInput.waitFor({ state: 'visible', timeout: 15_000 }); + return memberCreatePage; +}; + +/** Navigate to a member profile and open its editor. */ +export const openMemberProfileEditorFor = async (page: Page, communityId: string, routeMemberId: string, memberId: string): Promise => { + await page.goto(`/community/${encodeURIComponent(communityId)}/admin/${encodeURIComponent(routeMemberId)}/members/${encodeURIComponent(memberId)}/profile`, { waitUntil: 'networkidle' }); + const memberProfilePage = memberProfilePageOn(page); + await memberProfilePage.clickEditProfile(); + return memberProfilePage; +}; + +/** Navigate to a member account-assignment form and wait for its end-user selector. */ +export const openMemberAccountAssignmentFor = async (page: Page, communityId: string, routeMemberId: string, memberId: string): Promise => { + await page.goto(`/community/${encodeURIComponent(communityId)}/admin/${encodeURIComponent(routeMemberId)}/members/${encodeURIComponent(memberId)}/accounts/add`, { waitUntil: 'networkidle' }); + const memberAccountsPage = memberAccountsPageOn(page); + await memberAccountsPage.endUserSelect.waitFor({ state: 'visible', timeout: 15_000 }); + return memberAccountsPage; +}; + +/** Navigate to a member account list and wait for the account table to render. */ +export const openMemberAccountsListFor = async (page: Page, communityId: string, routeMemberId: string, memberId: string): Promise => { + await page.goto(`/community/${encodeURIComponent(communityId)}/admin/${encodeURIComponent(routeMemberId)}/members/${encodeURIComponent(memberId)}/accounts`, { waitUntil: 'networkidle' }); + const memberAccountsPage = memberAccountsPageOn(page); + await memberAccountsPage.addAccountButton.waitFor({ state: 'visible', timeout: 15_000 }); + return memberAccountsPage; +}; diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/fill-and-submit-member-create-form.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/fill-and-submit-member-create-form.ts new file mode 100644 index 000000000..22b026d8f --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/fill-and-submit-member-create-form.ts @@ -0,0 +1,31 @@ +import { type Actor, Interaction, notes, the } from '@serenity-js/core'; +import { communityPortalPageOf, memberCreatePageOn } from '../abilities/community-portal-page.ts'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; + +export const SubmitMemberCreateForm = (actor: Actor, memberName: string) => + Interaction.where(the`#actor submits the member create form for "${memberName}"`, async () => { + const page = communityPortalPageOf(actor); + const memberCreatePage = memberCreatePageOn(page); + await memberCreatePage.clickCreateMember(); + + await memberCreatePage.validationError.waitFor({ state: 'visible', timeout: 750 }).catch(() => undefined); + if (await memberCreatePage.validationError.isVisible().catch(() => false)) { + const errorText = await memberCreatePage.validationError.textContent(); + await actor.attemptsTo(notes().set('lastMemberId', null), notes().set('errorMessage', errorText || 'Validation error')); + return; + } + + await page.waitForURL(/\/members\/[^/]+$/, { timeout: 15_000 }).catch(async () => { + await memberCreatePage.errorToast.waitFor({ state: 'visible', timeout: 1_000 }).catch(() => undefined); + const message = (await memberCreatePage.errorToast.textContent().catch(() => null)) || `Member creation did not navigate to a member detail page for "${memberName}"`; + await actor.attemptsTo(notes().set('lastMemberId', null), notes().set('errorMessage', message)); + throw new Error(message); + }); + + const memberId = new URL(page.url()).pathname.match(/\/members\/([^/]+)$/)?.[1]; + if (!memberId) { + throw new Error(`Member creation navigated to an unexpected URL: ${page.url()}`); + } + + await actor.attemptsTo(notes().set('lastMemberId', decodeURIComponent(memberId)), notes().set('errorMessage', null)); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/fill-and-submit-member-profile-form.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/fill-and-submit-member-profile-form.ts new file mode 100644 index 000000000..83d92885f --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/fill-and-submit-member-profile-form.ts @@ -0,0 +1,29 @@ +import { type Actor, Interaction, notes, the } from '@serenity-js/core'; +import { communityPortalPageOf, memberProfilePageOn } from '../abilities/community-portal-page.ts'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; + +export const SubmitMemberProfileForm = (actor: Actor) => + Interaction.where(the`#actor submits the member profile form`, async () => { + const page = communityPortalPageOf(actor); + const memberProfilePage = memberProfilePageOn(page); + + await memberProfilePage.clickSaveProfile(); + await memberProfilePage.firstValidationError.waitFor({ state: 'visible', timeout: 750 }).catch(() => undefined); + if (await memberProfilePage.firstValidationError.isVisible().catch(() => false)) { + const errorText = await memberProfilePage.firstValidationError.textContent(); + await actor.attemptsTo(notes().set('errorMessage', errorText || 'Validation error')); + return; + } + + const didSave = await Promise.race([ + memberProfilePage.editProfileButton.waitFor({ state: 'visible', timeout: 15_000 }).then(() => true), + memberProfilePage.errorToast.waitFor({ state: 'visible', timeout: 15_000 }).then(() => false), + ]); + if (!didSave) { + const message = (await memberProfilePage.errorToast.textContent()) || 'Member profile update failed'; + await actor.attemptsTo(notes().set('errorMessage', message)); + throw new Error(message); + } + + await actor.attemptsTo(notes().set('errorMessage', null)); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/fill-member-create-form.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/fill-member-create-form.ts new file mode 100644 index 000000000..7737758cc --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/fill-member-create-form.ts @@ -0,0 +1,10 @@ +import { type Actor, Interaction, notes, the } from '@serenity-js/core'; +import { communityPortalPageOf, memberCreatePageOn } from '../abilities/community-portal-page.ts'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; + +export const FillMemberCreateForm = (actor: Actor, memberName: string) => + Interaction.where(the`#actor fills the member create form for "${memberName}"`, async () => { + const memberCreatePage = memberCreatePageOn(communityPortalPageOf(actor)); + await memberCreatePage.fillMemberName(memberName); + await actor.attemptsTo(notes().set('lastMemberName', memberName)); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/fill-member-profile-form.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/fill-member-profile-form.ts new file mode 100644 index 000000000..a479dcf32 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/fill-member-profile-form.ts @@ -0,0 +1,17 @@ +import { type Actor, Interaction, notes, the } from '@serenity-js/core'; +import { communityPortalPageOf, memberProfilePageOn } from '../abilities/community-portal-page.ts'; +import type { MemberE2ENotes, MemberProfileExpectation } from '../notes/member-notes.ts'; + +export const FillMemberProfileForm = (actor: Actor, profile: MemberProfileExpectation) => + Interaction.where(the`#actor fills the member profile form`, async () => { + const memberProfilePage = memberProfilePageOn(communityPortalPageOf(actor)); + if (profile.name !== undefined) await memberProfilePage.fillDisplayName(profile.name); + if (profile.email !== undefined) await memberProfilePage.fillEmail(profile.email); + if (profile.bio !== undefined) await memberProfilePage.fillBio(profile.bio); + if (profile.showInterests !== undefined) await memberProfilePage.setShowInterests(profile.showInterests); + if (profile.showEmail !== undefined) await memberProfilePage.setShowEmail(profile.showEmail); + if (profile.showProfile !== undefined) await memberProfilePage.setShowProfile(profile.showProfile); + if (profile.showLocation !== undefined) await memberProfilePage.setShowLocation(profile.showLocation); + if (profile.showProperties !== undefined) await memberProfilePage.setShowProperties(profile.showProperties); + await actor.attemptsTo(notes().set('lastExpectedMemberProfile', profile)); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/open-community-member-list.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/open-community-member-list.ts new file mode 100644 index 000000000..cd86fc36c --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/open-community-member-list.ts @@ -0,0 +1,13 @@ +import { type Actor, Interaction, the } from '@serenity-js/core'; +import { communityPortalPageOf, openMemberListFor } from '../abilities/community-portal-page.ts'; +import { CommunityId } from '../questions/community-id.ts'; +import { RouteMemberId } from '../questions/route-member-id.ts'; + +export const OpenCommunityMemberList = (actor: Actor, communityName: string) => + Interaction.where(the`#actor opens the member list for "${communityName}"`, async () => { + const page = communityPortalPageOf(actor); + const communityId = await actor.answer(CommunityId(communityName)); + const routeMemberId = await actor.answer(RouteMemberId(communityName)); + + await openMemberListFor(page, communityId, routeMemberId); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/open-create-member-form.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/open-create-member-form.ts new file mode 100644 index 000000000..eb4ee67bb --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/open-create-member-form.ts @@ -0,0 +1,13 @@ +import { type Actor, Interaction, the } from '@serenity-js/core'; +import { communityPortalPageOf, openMemberCreateFormFor } from '../abilities/community-portal-page.ts'; +import { CommunityId } from '../questions/community-id.ts'; +import { RouteMemberId } from '../questions/route-member-id.ts'; + +export const OpenCreateMemberForm = (actor: Actor, communityName: string) => + Interaction.where(the`#actor opens the create member form for "${communityName}"`, async () => { + const page = communityPortalPageOf(actor); + const communityId = await actor.answer(CommunityId(communityName)); + const routeMemberId = await actor.answer(RouteMemberId(communityName)); + + await openMemberCreateFormFor(page, communityId, routeMemberId); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/open-member-account-assignment.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/open-member-account-assignment.ts new file mode 100644 index 000000000..098885b61 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/open-member-account-assignment.ts @@ -0,0 +1,18 @@ +import { type Actor, Interaction, notes, the } from '@serenity-js/core'; +import { communityPortalPageOf, openMemberAccountAssignmentFor } from '../abilities/community-portal-page.ts'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; +import { CommunityId } from '../questions/community-id.ts'; +import { RouteMemberId } from '../questions/route-member-id.ts'; + +export const OpenMemberAccountAssignment = (actor: Actor, communityName: string) => + Interaction.where(the`#actor opens member account assignment in "${communityName}"`, async () => { + const page = communityPortalPageOf(actor); + const communityId = await actor.answer(CommunityId(communityName)); + const memberId = await actor.answer(notes().get('lastMemberId')); + if (!memberId) { + throw new Error(`Missing member state for account assignment in "${communityName}"`); + } + const routeMemberId = await actor.answer(RouteMemberId(communityName)); + + await openMemberAccountAssignmentFor(page, communityId, routeMemberId, memberId); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/open-member-profile-editor.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/open-member-profile-editor.ts new file mode 100644 index 000000000..0f2c5e57b --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/open-member-profile-editor.ts @@ -0,0 +1,18 @@ +import { type Actor, Interaction, notes, the } from '@serenity-js/core'; +import { communityPortalPageOf, openMemberProfileEditorFor } from '../abilities/community-portal-page.ts'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; +import { CommunityId } from '../questions/community-id.ts'; +import { RouteMemberId } from '../questions/route-member-id.ts'; + +export const OpenMemberProfileEditor = (actor: Actor, communityName: string, memberName: string) => + Interaction.where(the`#actor opens the profile editor for "${memberName}" in "${communityName}"`, async () => { + const page = communityPortalPageOf(actor); + const communityId = await actor.answer(CommunityId(communityName)); + const memberId = await actor.answer(notes().get('lastMemberId')); + if (!memberId) { + throw new Error(`Missing member state for profile update in "${communityName}"`); + } + const routeMemberId = await actor.answer(RouteMemberId(communityName)); + + await openMemberProfileEditorFor(page, communityId, routeMemberId, memberId); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/remove-member.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/remove-member.ts new file mode 100644 index 000000000..f1d3fbc21 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/remove-member.ts @@ -0,0 +1,42 @@ +import { type Actor, Interaction, notes, the } from '@serenity-js/core'; +import { communityPortalPageOf, openMemberListFor } from '../abilities/community-portal-page.ts'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; +import { CommunityId } from '../questions/community-id.ts'; +import { HasNoMemberForCommunity } from '../questions/has-no-member-for-community.ts'; +import { RouteMemberId } from '../questions/route-member-id.ts'; + +export const RemoveMember = (actor: Actor, communityName: string, memberName: string) => + Interaction.where(the`#actor removes member "${memberName}" from "${communityName}"`, async () => { + const page = communityPortalPageOf(actor); + const communityId = await actor.answer(CommunityId(communityName)); + const routeMemberId = await actor.answer(RouteMemberId(communityName)); + + let memberListPage: Awaited>; + try { + memberListPage = await openMemberListFor(page, communityId, routeMemberId); + } catch (error) { + if (await actor.answer(HasNoMemberForCommunity.inCommunity(communityId))) { + const message = `Unauthorized: no community membership for "${communityName}"`; + await actor.attemptsTo(notes().set('errorMessage', message)); + throw new Error(message); + } + throw error; + } + await memberListPage.memberName(memberName).waitFor({ state: 'visible', timeout: 15_000 }); + await memberListPage.clickRemoveMember(memberName); + + const outcome = await Promise.race([ + memberListPage + .memberName(memberName) + .waitFor({ state: 'hidden', timeout: 15_000 }) + .then(() => 'removed' as const), + memberListPage.errorToast.waitFor({ state: 'visible', timeout: 15_000 }).then(() => 'denied' as const), + ]); + if (outcome === 'denied') { + const message = (await memberListPage.errorToast.textContent()) || 'Member removal was denied'; + await actor.attemptsTo(notes().set('errorMessage', message)); + throw new Error(message); + } + + await actor.attemptsTo(notes().set('errorMessage', null)); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/resolve-community-administrator-membership.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/resolve-community-administrator-membership.ts new file mode 100644 index 000000000..71db1f81d --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/resolve-community-administrator-membership.ts @@ -0,0 +1,46 @@ +import { type Actor, Interaction, notes, the } from '@serenity-js/core'; +import type { Response } from 'playwright'; +import { communityPortalPageOf } from '../abilities/community-portal-page.ts'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; +import { CommunityId } from '../questions/community-id.ts'; + +const membersForCurrentEndUserOperationName = 'AccountsCommunityListContainerMembersForCurrentEndUser'; + +type GraphqlPayload = { + data?: TData; + errors?: Array<{ message?: string }>; +}; + +type MembersForCurrentEndUserPayload = GraphqlPayload<{ + membersForCurrentEndUser?: Array<{ + id: string; + isAdmin?: boolean | null; + community?: { id: string } | null; + }>; +}>; + +const hasGraphqlOperation = (operationName: string) => (response: Response) => response.url().includes('/api/graphql') && response.request().method() === 'POST' && (response.request().postData()?.includes(operationName) ?? false); + +const selectPayload = (payload: GraphqlPayload | GraphqlPayload[] | null, hasExpectedData: (data: TData | undefined) => boolean): GraphqlPayload | null => { + if (!Array.isArray(payload)) { + return payload; + } + + return payload.find((item) => hasExpectedData(item.data)) ?? payload.find((item) => item.errors?.length) ?? null; +}; + +export const ResolveCommunityAdministratorMembership = (actor: Actor, communityName: string) => + Interaction.where(the`#actor resolves administrator membership for "${communityName}"`, async () => { + const page = communityPortalPageOf(actor); + const communityId = await actor.answer(CommunityId(communityName)); + + const membershipsResponse = page.waitForResponse(hasGraphqlOperation(membersForCurrentEndUserOperationName), { timeout: 15_000 }); + await page.goto('/community/accounts', { waitUntil: 'networkidle' }); + const membershipsPayload = selectPayload((await (await membershipsResponse).json()) as MembersForCurrentEndUserPayload | MembersForCurrentEndUserPayload[], (data) => Boolean(data?.membersForCurrentEndUser)); + const routeMemberId = membershipsPayload?.data?.membersForCurrentEndUser?.find((member) => member.isAdmin && member.community?.id === communityId)?.id; + if (!routeMemberId) { + throw new Error(`No administrator membership found for community "${communityName}"`); + } + + await actor.attemptsTo(notes().set('routeMemberId', routeMemberId)); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/search-member-list.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/search-member-list.ts new file mode 100644 index 000000000..77a3c2745 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/search-member-list.ts @@ -0,0 +1,8 @@ +import { type Actor, Interaction, the } from '@serenity-js/core'; +import { communityPortalPageOf, memberListPageOn } from '../abilities/community-portal-page.ts'; + +export const SearchMemberList = (actor: Actor, searchTerm: string) => + Interaction.where(the`#actor searches the member list for "${searchTerm}"`, async () => { + const memberListPage = memberListPageOn(communityPortalPageOf(actor)); + await memberListPage.searchByMemberName(searchTerm); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/select-member-end-user-account.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/select-member-end-user-account.ts new file mode 100644 index 000000000..9c86dba2b --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/select-member-end-user-account.ts @@ -0,0 +1,8 @@ +import { type Actor, Interaction, the } from '@serenity-js/core'; +import { communityPortalPageOf, memberAccountsPageOn } from '../abilities/community-portal-page.ts'; + +export const SelectMemberEndUserAccount = (actor: Actor, displayName: string) => + Interaction.where(the`#actor selects end-user account "${displayName}"`, async () => { + const memberAccountsPage = memberAccountsPageOn(communityPortalPageOf(actor)); + await memberAccountsPage.selectEndUser(displayName); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/submit-member-account-assignment.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/submit-member-account-assignment.ts new file mode 100644 index 000000000..9a40c168f --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/interactions/submit-member-account-assignment.ts @@ -0,0 +1,20 @@ +import { type Actor, Interaction, notes, the } from '@serenity-js/core'; +import { communityPortalPageOf, memberAccountsPageOn } from '../abilities/community-portal-page.ts'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; + +export const SubmitMemberAccountAssignment = (actor: Actor) => + Interaction.where(the`#actor submits the member account assignment`, async () => { + const page = communityPortalPageOf(actor); + const memberAccountsPage = memberAccountsPageOn(page); + const accountsListNavigation = page.waitForURL(/\/members\/[^/]+\/accounts\/?$/, { timeout: 15_000 }); + const assignmentError = memberAccountsPage.errorToast.waitFor({ state: 'visible', timeout: 15_000 }); + await memberAccountsPage.clickAddMemberAccount(); + const outcome = await Promise.race([accountsListNavigation.then(() => 'navigated' as const), assignmentError.then(() => 'error' as const)]).catch(() => 'timed-out' as const); + if (outcome !== 'navigated') { + const message = (await memberAccountsPage.errorToast.textContent().catch(() => null)) || `Member account assignment did not complete; current URL: ${page.url()}`; + await actor.attemptsTo(notes().set('errorMessage', message)); + throw new Error(message); + } + + await actor.attemptsTo(notes().set('errorMessage', null)); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/notes/member-notes.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/notes/member-notes.ts new file mode 100644 index 000000000..97ba400ca --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/notes/member-notes.ts @@ -0,0 +1,28 @@ +export interface MemberProfileExpectation { + name?: string; + email?: string; + bio?: string; + avatarDocumentId?: string; + interests?: string[]; + showInterests?: boolean; + showEmail?: boolean; + showProfile?: boolean; + showLocation?: boolean; + showProperties?: boolean; +} + +export interface MemberE2ENotes { + communityIdsByName: Record; + endUserEmailsByLabel: Record; + endUserDisplayNamesByLabel: Record; + endUserExternalIdsByLabel: Record; + lastMemberCommunityId: string | null; + lastMemberCommunityName: string | null; + lastMemberId: string | null; + lastMemberName: string; + lastExpectedMemberProfile?: MemberProfileExpectation; + lastUpdatedMemberProfile?: MemberProfileExpectation; + lastMemberStatus: string | null; + errorMessage: string | null; + routeMemberId: string | null; +} diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/questions/community-id.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/community-id.ts new file mode 100644 index 000000000..269568184 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/community-id.ts @@ -0,0 +1,12 @@ +import { notes, Question } from '@serenity-js/core'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; + +export const CommunityId = (communityName: string) => + Question.about(`the ID of community "${communityName}"`, async (actor) => { + const communityIdsByName = await actor.answer(notes().get('communityIdsByName')); + const communityId = communityIdsByName[communityName]; + if (!communityId) { + throw new Error(`Unknown community "${communityName}". Ensure it was created in setup.`); + } + return communityId; + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/questions/has-no-member-for-community.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/has-no-member-for-community.ts new file mode 100644 index 000000000..bbd37cdd6 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/has-no-member-for-community.ts @@ -0,0 +1,40 @@ +import { BrowseTheWeb } from '@cellix/serenity-framework/serenity/browser'; +import { type AnswersQuestions, Question, type UsesAbilities } from '@serenity-js/core'; +import type { Response } from 'playwright'; + +const membersForCurrentEndUserOperationName = 'AccountsCommunityListContainerMembersForCurrentEndUser'; + +type MembersForCurrentEndUserPayload = { + data?: { + membersForCurrentEndUser?: Array<{ + community?: { id: string } | null; + }>; + }; +}; + +const hasGraphqlOperation = (operationName: string) => (response: Response) => response.url().includes('/api/graphql') && response.request().method() === 'POST' && (response.request().postData()?.includes(operationName) ?? false); + +export class HasNoMemberForCommunity extends Question> { + static inCommunity(communityId: string): HasNoMemberForCommunity { + return new HasNoMemberForCommunity(communityId); + } + + private constructor(private readonly communityId: string) { + super(`whether the current end user has no member in community "${communityId}"`); + } + + override async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise { + const { page } = BrowseTheWeb.withActor(actor); + const membershipsResponse = page.waitForResponse(hasGraphqlOperation(membersForCurrentEndUserOperationName), { timeout: 15_000 }); + await page.goto('/community/accounts', { waitUntil: 'networkidle' }); + const membershipsPayload = (await (await membershipsResponse).json()) as MembersForCurrentEndUserPayload | MembersForCurrentEndUserPayload[]; + const payload = Array.isArray(membershipsPayload) ? membershipsPayload.find((item) => item.data?.membersForCurrentEndUser) : membershipsPayload; + const members = payload?.data?.membersForCurrentEndUser; + + if (!members) { + throw new Error('Unable to determine memberships for the current end user'); + } + + return !members.some((member) => member.community?.id === this.communityId); + } +} diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-account-linked.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-account-linked.ts new file mode 100644 index 000000000..7199f9dfc --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-account-linked.ts @@ -0,0 +1,28 @@ +import { type Actor, notes, Question } from '@serenity-js/core'; +import { communityPortalPageOf, openMemberAccountsListFor } from '../abilities/community-portal-page.ts'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; +import { CommunityId } from './community-id.ts'; + +const openAccountsList = async (actor: Actor, communityName: string) => { + const memberId = await actor.answer(notes().get('lastMemberId')); + const routeMemberId = await actor.answer(notes().get('routeMemberId')); + if (!memberId || !routeMemberId) { + throw new Error(`Missing member or route member state for account verification in "${communityName}"`); + } + + return openMemberAccountsListFor(communityPortalPageOf(actor), await actor.answer(CommunityId(communityName)), routeMemberId, memberId); +}; + +export const MemberAccountLinked = (communityName: string, email: string) => + Question.about(`whether the member account list contains "${email}" in "${communityName}"`, async (serenityActor) => { + const actor = serenityActor as unknown as Actor; + const memberAccountsPage = await openAccountsList(actor, communityName); + await memberAccountsPage.linkedAccountEmail(email).waitFor({ state: 'visible', timeout: 15_000 }); + return await memberAccountsPage.linkedAccountEmail(email).isVisible(); + }); + +export const MemberAccountCount = (communityName: string, email: string) => + Question.about(`the number of rendered member account links for "${email}" in "${communityName}"`, async (serenityActor) => { + const actor = serenityActor as unknown as Actor; + return (await openAccountsList(actor, communityName)).linkedAccountCount(email); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-created-in-community.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-created-in-community.ts new file mode 100644 index 000000000..3f52285f1 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-created-in-community.ts @@ -0,0 +1,19 @@ +import { type Actor, notes, Question } from '@serenity-js/core'; +import { communityPortalPageOf, openMemberListFor } from '../abilities/community-portal-page.ts'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; +import { CommunityId } from './community-id.ts'; + +export const MemberCreatedInCommunity = (communityName: string) => + Question.about(`whether the created member appears in "${communityName}"`, async (serenityActor) => { + const actor = serenityActor as unknown as Actor; + const memberName = await actor.answer(notes().get('lastMemberName')); + const routeMemberId = await actor.answer(notes().get('routeMemberId')); + if (!memberName || !routeMemberId) { + throw new Error(`Missing created member or route member state for "${communityName}"`); + } + + const communityId = await actor.answer(CommunityId(communityName)); + const memberListPage = await openMemberListFor(communityPortalPageOf(actor), communityId, routeMemberId); + await memberListPage.memberName(memberName).waitFor({ state: 'visible', timeout: 15_000 }); + return true; + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-error-message.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-error-message.ts new file mode 100644 index 000000000..83576feb6 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-error-message.ts @@ -0,0 +1,4 @@ +import { notes, Question } from '@serenity-js/core'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; + +export const MemberErrorMessage = () => Question.about('the member validation error', (actor) => actor.answer(notes().get('errorMessage'))); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-listed-in-community.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-listed-in-community.ts new file mode 100644 index 000000000..04bebe24f --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-listed-in-community.ts @@ -0,0 +1,15 @@ +import { PlaywrightPageAdapter } from '@cellix/serenity-framework/pages/playwright'; +import { BrowseTheWeb } from '@cellix/serenity-framework/serenity/browser'; +import { MemberListPage } from '@ocom-verification/verification-shared/pages'; +import { type Actor, Question } from '@serenity-js/core'; + +export const MemberListedInCommunity = (memberName: string, route?: { communityId: string; routeMemberId: string }) => + Question.about(`whether member "${memberName}" appears in the browser member list`, async (serenityActor) => { + const actor = serenityActor as unknown as Actor; + const { page } = BrowseTheWeb.withActor(actor); + if (route) { + await page.goto(`/community/${encodeURIComponent(route.communityId)}/admin/${encodeURIComponent(route.routeMemberId)}/members`, { waitUntil: 'networkidle' }); + } + const memberListPage = new MemberListPage(new PlaywrightPageAdapter(page)); + return await memberListPage.memberName(memberName).isVisible(); + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-profile-matches.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-profile-matches.ts new file mode 100644 index 000000000..4e71bfae5 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-profile-matches.ts @@ -0,0 +1,37 @@ +import { type Actor, notes, Question } from '@serenity-js/core'; +import { communityPortalPageOf, openMemberProfileEditorFor } from '../abilities/community-portal-page.ts'; +import type { MemberE2ENotes, MemberProfileExpectation } from '../notes/member-notes.ts'; +import { CommunityId } from './community-id.ts'; + +const assertProfileValue = (name: string, actual: string | boolean, expected: string | boolean) => { + if (actual !== expected) { + throw new Error(`Expected member profile ${name} to be "${expected}", got "${actual}"`); + } +}; + +export const MemberProfileMatches = (communityName: string) => + Question.about(`whether the member profile matches the expected values in "${communityName}"`, async (serenityActor) => { + const actor = serenityActor as unknown as Actor; + const profile = await actor.answer(notes().get('lastExpectedMemberProfile')); + const memberId = await actor.answer(notes().get('lastMemberId')); + const routeMemberId = await actor.answer(notes().get('routeMemberId')); + if (!profile || !memberId || !routeMemberId) { + throw new Error(`Missing profile, member, or route member state for "${communityName}"`); + } + + const communityId = await actor.answer(CommunityId(communityName)); + const page = await openMemberProfileEditorFor(communityPortalPageOf(actor), communityId, routeMemberId, memberId); + await verifyProfile(page, profile); + return true; + }); + +const verifyProfile = async (page: Awaited>, profile: MemberProfileExpectation) => { + if (profile.name !== undefined) assertProfileValue('name', await page.displayNameValue(), profile.name); + if (profile.email !== undefined) assertProfileValue('email', await page.emailValue(), profile.email); + if (profile.bio !== undefined) assertProfileValue('bio', await page.bioValue(), profile.bio); + if (profile.showInterests !== undefined) assertProfileValue('showInterests', await page.showInterestsValue(), profile.showInterests); + if (profile.showEmail !== undefined) assertProfileValue('showEmail', await page.showEmailValue(), profile.showEmail); + if (profile.showProfile !== undefined) assertProfileValue('showProfile', await page.showProfileValue(), profile.showProfile); + if (profile.showLocation !== undefined) assertProfileValue('showLocation', await page.showLocationValue(), profile.showLocation); + if (profile.showProperties !== undefined) assertProfileValue('showProperties', await page.showPropertiesValue(), profile.showProperties); +}; diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-removed-from-community.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-removed-from-community.ts new file mode 100644 index 000000000..65da1f125 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-removed-from-community.ts @@ -0,0 +1,17 @@ +import { type Actor, notes, Question } from '@serenity-js/core'; +import { communityPortalPageOf, openMemberListFor } from '../abilities/community-portal-page.ts'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; +import { CommunityId } from './community-id.ts'; + +export const MemberRemovedFromCommunity = (communityName: string, memberName: string) => + Question.about(`whether member "${memberName}" is absent from "${communityName}"`, async (serenityActor) => { + const actor = serenityActor as unknown as Actor; + const routeMemberId = await actor.answer(notes().get('routeMemberId')); + if (!routeMemberId) { + throw new Error(`Missing route member state for member removal verification in "${communityName}"`); + } + + const memberListPage = await openMemberListFor(communityPortalPageOf(actor), await actor.answer(CommunityId(communityName)), routeMemberId); + await memberListPage.memberName(memberName).waitFor({ state: 'hidden', timeout: 15_000 }); + return true; + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/questions/route-member-id.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/route-member-id.ts new file mode 100644 index 000000000..f0f5797e3 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/questions/route-member-id.ts @@ -0,0 +1,12 @@ +import { notes, Question } from '@serenity-js/core'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; + +export const RouteMemberId = (communityName: string) => + Question.about(`the administrator route member ID for "${communityName}"`, async (actor) => { + const routeMemberId = await actor.answer(notes().get('routeMemberId')); + if (!routeMemberId) { + throw new Error(`Missing administrator route member state for "${communityName}"`); + } + + return routeMemberId; + }); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/assign-member-account.steps.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/assign-member-account.steps.ts new file mode 100644 index 000000000..1e989059a --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/assign-member-account.steps.ts @@ -0,0 +1,70 @@ +import { Given, Then, When } from '@cucumber/cucumber'; +import { actors } from '@ocom-verification/verification-shared/test-data'; +import { actorCalled, actorInTheSpotlight, notes } from '@serenity-js/core'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; +import { MemberAccountCount, MemberAccountLinked } from '../questions/member-account-linked.ts'; +import { AssignMemberAccount } from '../tasks/assign-member-account.ts'; + +const accountDetails: Record = { + Charlie: { + displayName: `${actors.CommunityOwner.givenName} ${actors.CommunityOwner.familyName}`, + email: actors.CommunityOwner.email, + externalId: actors.CommunityOwner.externalId, + }, +}; + +Given('end-user account {string} is available for assignment in {string}', async (accountLabel: string, communityName: string) => { + const actor = actorInTheSpotlight(); + const account = accountDetails[accountLabel]; + if (!account) { + throw new Error(`Unknown end-user account label "${accountLabel}"`); + } + await actor.attemptsTo( + notes().set('endUserDisplayNamesByLabel', { [accountLabel]: account.displayName }), + notes().set('endUserEmailsByLabel', { [accountLabel]: account.email }), + notes().set('endUserExternalIdsByLabel', { [accountLabel]: account.externalId }), + notes().set('lastMemberCommunityName', communityName), + ); +}); + +When('{word} associates end-user account {string} to member {string} in {string}', async (actorName: string, accountLabel: string, _memberName: string, communityName: string) => { + const actor = actorCalled(actorName); + const displayNames = await actor.answer(notes().get('endUserDisplayNamesByLabel')); + await actor.attemptsTo(notes().set('errorMessage', null)); + try { + await actor.attemptsTo(AssignMemberAccount(communityName, displayNames[accountLabel] ?? '')); + } catch (error) { + await actor.attemptsTo(notes().set('errorMessage', error instanceof Error ? error.message : String(error))); + } +}); + +Given('member {string} is already linked to end-user account {string}', async (_memberName: string, accountLabel: string) => { + const actor = actorInTheSpotlight(); + const displayNames = await actor.answer(notes().get('endUserDisplayNamesByLabel')); + await actor.attemptsTo(AssignMemberAccount('Green Oaks', displayNames[accountLabel] ?? '')); +}); + +Then('member {string} should be linked to end-user account {string}', async (_memberName: string, accountLabel: string) => { + const actor = actorInTheSpotlight(); + const emails = await actor.answer(notes().get('endUserEmailsByLabel')); + const communityName = await actor.answer(notes().get('lastMemberCommunityName')); + if (!communityName) { + throw new Error('Missing community state for account verification'); + } + if (!(await actor.answer(MemberAccountLinked(communityName, emails[accountLabel] ?? '')))) { + throw new Error(`Expected the member account list to contain end-user account "${accountLabel}"`); + } +}); + +Then('member {string} should remain linked to end-user account {string} only once', async (_memberName: string, accountLabel: string) => { + const actor = actorInTheSpotlight(); + const emails = await actor.answer(notes().get('endUserEmailsByLabel')); + const communityName = await actor.answer(notes().get('lastMemberCommunityName')); + if (!communityName) { + throw new Error('Missing community state for account verification'); + } + const count = await actor.answer(MemberAccountCount(communityName, emails[accountLabel] ?? '')); + if (count !== 1) { + throw new Error(`Expected one account association for "${accountLabel}" but found ${count}`); + } +}); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/create-member.steps.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/create-member.steps.ts new file mode 100644 index 000000000..f6bc297f7 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/create-member.steps.ts @@ -0,0 +1,95 @@ +import { GherkinDataTable } from '@cellix/serenity-framework/cucumber/gherkin-data-table'; +import { type DataTable, Given, Then, When } from '@cucumber/cucumber'; +import { actors } from '@ocom-verification/verification-shared/test-data'; +import { actorCalled, notes } from '@serenity-js/core'; +import { LogInWithOAuth2 } from '../../../shared/abilities/oauth2-login.ts'; +import { clearKnownQueueMessages } from '../../../shared/support/queue-storage.ts'; +import type { CommunityE2ENotes } from '../notes/community-notes.ts'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; +import { MemberCreatedInCommunity } from '../questions/member-created-in-community.ts'; +import { MemberErrorMessage } from '../questions/member-error-message.ts'; +import { CreateCommunity } from '../tasks/create-community.ts'; +import { CreateMember } from '../tasks/create-member.ts'; + +interface MemberDetails { + memberName?: string; +} + +let lastActorName = actors.CommunityOwner.name; + +Given('{word} is signed in as a community owner for member management', async (actorName: string) => { + lastActorName = actorName; + const actor = actorCalled(actorName); + + await clearKnownQueueMessages(); + await actor.attemptsTo(LogInWithOAuth2(actors.CommunityOwner.email)); +}); + +Given('{word} has a community named {string}', async (actorName: string, communityName: string) => { + lastActorName = actorName; + const actor = actorCalled(actorName); + + await actor.attemptsTo(CreateCommunity(communityName)); + + const communityId = (await actor.answer(notes().get('communityId'))) as string | null; + if (!communityId) { + throw new Error(`Expected created community id for "${communityName}" but none was recorded`); + } + + const existingCommunityIdsByName = (await actor.answer(notes().get('communityIdsByName')).catch(() => ({}) as Record)) as Record; + await actor.attemptsTo( + notes().set('communityIdsByName', { + ...existingCommunityIdsByName, + [communityName]: communityId, + }), + ); +}); + +When('{word} creates a member in {string} with:', async (actorName: string, communityName: string, dataTable: DataTable) => { + lastActorName = actorName; + const actor = actorCalled(actorName); + + const details = GherkinDataTable.from(dataTable).rowsHash(); + const memberName = details.memberName?.trim() ?? ''; + if (!memberName) { + throw new Error('memberName is required'); + } + + await actor.attemptsTo(notes().set('lastMemberId', null), notes().set('errorMessage', null)); + + await actor.attemptsTo(CreateMember(communityName, memberName)); +}); + +Then('the member should be created successfully in {string}', async (communityName: string) => { + const actor = actorCalled(lastActorName); + await actor.answer(MemberCreatedInCommunity(communityName)); +}); + +When('{word} attempts to create a member in {string} with:', async (actorName: string, communityName: string, dataTable: DataTable) => { + lastActorName = actorName; + const actor = actorCalled(actorName); + const details = GherkinDataTable.from(dataTable).rowsHash(); + await actor.attemptsTo(notes().set('lastMemberId', null), notes().set('errorMessage', null)); + try { + await actor.attemptsTo(CreateMember(communityName, details.memberName?.trim() ?? '')); + } catch (error) { + await actor.attemptsTo(notes().set('errorMessage', error instanceof Error ? error.message : String(error))); + } +}); + +Then('she should see a member error for {string}', async (fieldName: string) => { + const error = await actorCalled(lastActorName).answer(MemberErrorMessage()); + const isFieldMentioned = error?.toLowerCase().includes(fieldName.toLowerCase()) ?? false; + if (!error || (!isFieldMentioned && !/cannot be empty|required|missing|invalid|must not be empty|please input|already associated/i.test(error))) { + throw new Error(`Expected a validation error related to "${fieldName}", but got: "${error}"`); + } +}); + +Then('no new member should be created in {string}', async (_communityName: string) => { + const memberId = await actorCalled(lastActorName) + .answer(notes().get('lastMemberId')) + .catch(() => null); + if (memberId) { + throw new Error('Expected no member to be created'); + } +}); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/index.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/index.ts index c04c54d61..02ccfb616 100644 --- a/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/index.ts +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/index.ts @@ -1,2 +1,7 @@ // Community context step definitions import './create-community.steps.ts'; +import './create-member.steps.ts'; +import './list-members.steps.ts'; +import './remove-member.steps.ts'; +import './assign-member-account.steps.ts'; +import './update-member.steps.ts'; diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/list-members.steps.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/list-members.steps.ts new file mode 100644 index 000000000..f942e8d84 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/list-members.steps.ts @@ -0,0 +1,60 @@ +import { type DataTable, Given, Then, When } from '@cucumber/cucumber'; +import { actors } from '@ocom-verification/verification-shared/test-data'; +import { actorCalled, actorInTheSpotlight, notes } from '@serenity-js/core'; +import { LogInWithOAuth2 } from '../../../shared/abilities/oauth2-login.ts'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; +import { MemberListedInCommunity } from '../questions/member-listed-in-community.ts'; +import { CreateMember } from '../tasks/create-member.ts'; +import { ListMembers } from '../tasks/list-members.ts'; +import { SearchMemberList } from '../tasks/search-member-list.ts'; + +interface ListedMemberDetails { + memberName: string; + role?: string; +} + +Given('{word} is an authenticated community admin for {string}', async (actorName: string, communityName: string) => { + const owner = actorInTheSpotlight(); + const communityIdsByName = await owner.answer(notes().get('communityIdsByName')); + if (!communityIdsByName[communityName]) { + throw new Error(`Unknown community "${communityName}". Ensure it was created in setup.`); + } + + await actorCalled(actorName).attemptsTo(notes().set('communityIdsByName', communityIdsByName), LogInWithOAuth2(actors.CommunityOwner.email)); +}); + +Given('the following members exist in {string}:', async (communityName: string, dataTable: DataTable) => { + const actor = actorInTheSpotlight(); + for (const { memberName } of dataTable.hashes() as ListedMemberDetails[]) { + await actor.attemptsTo(CreateMember(communityName, memberName.trim())); + } +}); + +When('{word} lists members for {string}', async (actorName: string, communityName: string) => { + await actorCalled(actorName).attemptsTo(ListMembers(communityName)); +}); + +When('{word} searches the member list in {string} for {string}', async (actorName: string, communityName: string, searchTerm: string) => { + await actorCalled(actorName).attemptsTo(ListMembers(communityName), SearchMemberList(searchTerm)); +}); + +Then('{word} should see the following members in {string}:', async (actorName: string, _communityName: string, dataTable: DataTable) => { + const actor = actorCalled(actorName); + for (const { memberName } of dataTable.hashes() as ListedMemberDetails[]) { + if (!(await actor.answer(MemberListedInCommunity(memberName)))) { + throw new Error(`Expected member "${memberName}" to appear in the browser member list`); + } + } +}); + +Then('{word} should not see member {string} from {string}', async (actorName: string, memberName: string, _communityName: string) => { + if (await actorCalled(actorName).answer(MemberListedInCommunity(memberName))) { + throw new Error(`Expected member "${memberName}" not to appear in the browser member list`); + } +}); + +Then('{word} should not see member {string} in the filtered results', async (actorName: string, memberName: string) => { + if (await actorCalled(actorName).answer(MemberListedInCommunity(memberName))) { + throw new Error(`Expected member "${memberName}" not to appear in the filtered member list`); + } +}); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/remove-member.steps.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/remove-member.steps.ts new file mode 100644 index 000000000..84e38fc4d --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/remove-member.steps.ts @@ -0,0 +1,83 @@ +import { BrowseTheWeb } from '@cellix/serenity-framework/serenity/browser'; +import { Given, Then, When } from '@cucumber/cucumber'; +import { actors } from '@ocom-verification/verification-shared/test-data'; +import { actorCalled, actorInTheSpotlight, notes } from '@serenity-js/core'; +import { SwitchOAuth2User } from '../../../shared/abilities/oauth2-login.ts'; +import type { MemberE2ENotes } from '../notes/member-notes.ts'; +import { HasNoMemberForCommunity } from '../questions/has-no-member-for-community.ts'; +import { MemberListedInCommunity } from '../questions/member-listed-in-community.ts'; +import { MemberRemovedFromCommunity } from '../questions/member-removed-from-community.ts'; +import { RemoveMember } from '../tasks/remove-member.ts'; + +let lastActorName = actors.CommunityOwner.name; +let managementOwnerActorName = actors.CommunityOwner.name; +let managementOwnerMemberId = ''; + +Given('{word} is signed in without membership in {string}', async (actorName: string, communityName: string) => { + const owner = actorInTheSpotlight(); + managementOwnerActorName = owner.name; + const communityIds = await owner.answer(notes().get('communityIdsByName')); + const targetMemberId = await owner.answer(notes().get('lastMemberId')); + const { page } = BrowseTheWeb.withActor(owner); + managementOwnerMemberId = new URL(page.url()).pathname.match(/\/admin\/([^/]+)\/members\//)?.[1] ?? ''; + const actor = actorCalled(actorName); + await actor.attemptsTo( + notes().set('communityIdsByName', communityIds), + notes().set('lastMemberId', targetMemberId), + notes().set('routeMemberId', targetMemberId), + notes().set('errorMessage', null), + SwitchOAuth2User('test@example.com'), + ); + if (!communityIds[communityName] || !managementOwnerMemberId) { + throw new Error(`Missing owner state for authorization scenario in "${communityName}"`); + } + if (!(await actor.answer(HasNoMemberForCommunity.inCommunity(communityIds[communityName])))) { + throw new Error(`Expected ${actorName} to have no membership in community "${communityName}"`); + } +}); + +When('{word} removes member {string} from {string}', async (actorName: string, memberName: string, communityName: string) => { + lastActorName = actorName; + const actor = actorCalled(actorName); + await actor.attemptsTo(RemoveMember(communityName, memberName)); +}); + +Then('the member should be removed successfully from {string}', async (communityName: string) => { + const actor = actorCalled(lastActorName); + const memberName = await actor.answer(notes().get('lastMemberName')); + if (!memberName || !(await actor.answer(MemberRemovedFromCommunity(communityName, memberName)))) { + throw new Error('Expected member removal to succeed'); + } +}); + +Then('member {string} should not appear in member listings for {string}', async (memberName: string, _communityName: string) => { + if (await actorCalled(lastActorName).answer(MemberListedInCommunity(memberName))) { + throw new Error(`Expected member "${memberName}" not to appear in the browser member list`); + } +}); + +When('{word} attempts to remove member {string} from {string}', async (actorName: string, memberName: string, communityName: string) => { + lastActorName = actorName; + const actor = actorCalled(actorName); + try { + await actor.attemptsTo(RemoveMember(communityName, memberName)); + } catch (error) { + await actor.attemptsTo(notes().set('errorMessage', error instanceof Error ? error.message : String(error))); + } +}); + +Then('{word} should receive an authorization error for member management', async (actorName: string) => { + const error = await actorCalled(actorName).answer(notes().get('errorMessage')); + if (!error || !/permission|cannot remove|unauthorized|forbidden|not authorized|not a member/i.test(error)) { + throw new Error(`Expected a member-management authorization error, but got: "${error}"`); + } +}); + +Then('member {string} should remain in {string}', async (memberName: string, communityName: string) => { + const owner = actorCalled(managementOwnerActorName); + const communityIds = await owner.answer(notes().get('communityIdsByName')); + await owner.attemptsTo(SwitchOAuth2User(actors.CommunityOwner.email)); + if (!(await owner.answer(MemberListedInCommunity(memberName, { communityId: communityIds[communityName] ?? '', routeMemberId: managementOwnerMemberId })))) { + throw new Error(`Expected member "${memberName}" to remain in "${communityName}"`); + } +}); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/update-member.steps.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/update-member.steps.ts new file mode 100644 index 000000000..6b56ce9c9 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/update-member.steps.ts @@ -0,0 +1,60 @@ +import { GherkinDataTable } from '@cellix/serenity-framework/cucumber/gherkin-data-table'; +import { type DataTable, Then, When } from '@cucumber/cucumber'; +import { actors } from '@ocom-verification/verification-shared/test-data'; +import { actorCalled, notes } from '@serenity-js/core'; +import type { MemberE2ENotes, MemberProfileExpectation } from '../notes/member-notes.ts'; +import { MemberProfileMatches } from '../questions/member-profile-matches.ts'; +import { UpdateMemberProfile } from '../tasks/update-member-profile.ts'; + +let lastActorName = actors.CommunityOwner.name; + +type MemberProfileUpdateDetails = Partial>; + +const parseBoolean = (value: string): boolean => value.trim().toLowerCase() === 'true'; + +When('{word} updates member {string} in {string} with:', async (actorName: string, memberName: string, communityName: string, dataTable: DataTable) => { + lastActorName = actorName; + + const actor = actorCalled(actorName); + const details = GherkinDataTable.from(dataTable).rowsHash(); + const communityIdsByName = (await actor.answer(notes().get('communityIdsByName')).catch(() => ({}) as Record)) as Record; + + if (!communityIdsByName[communityName]) { + throw new Error(`Unknown community "${communityName}". Ensure it was created in setup.`); + } + + const expectedProfile: MemberProfileExpectation = { + ...(details.name ? { name: details.name } : {}), + ...(details.memberName ? { name: details.memberName } : {}), + ...(details.email ? { email: details.email } : {}), + ...(details.bio ? { bio: details.bio } : {}), + ...(details.avatarDocumentId ? { avatarDocumentId: details.avatarDocumentId } : {}), + ...(details.interests + ? { + interests: details.interests + .split(',') + .map((interest) => interest.trim()) + .filter((interest) => interest.length > 0), + } + : {}), + ...(details.showInterests !== undefined ? { showInterests: parseBoolean(details.showInterests) } : {}), + ...(details.showEmail !== undefined ? { showEmail: parseBoolean(details.showEmail) } : {}), + ...(details.showProfile !== undefined ? { showProfile: parseBoolean(details.showProfile) } : {}), + ...(details.showLocation !== undefined ? { showLocation: parseBoolean(details.showLocation) } : {}), + ...(details.showProperties !== undefined ? { showProperties: parseBoolean(details.showProperties) } : {}), + }; + + await actor.attemptsTo(notes().set('errorMessage', null)); + + await actor.attemptsTo( + UpdateMemberProfile({ + communityName, + memberName, + profile: expectedProfile, + }), + ); +}); + +Then('the member should be updated successfully in {string}', async (_communityName: string) => { + await actorCalled(lastActorName).answer(MemberProfileMatches(_communityName)); +}); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/assign-member-account.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/assign-member-account.ts new file mode 100644 index 000000000..236c9a588 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/assign-member-account.ts @@ -0,0 +1,14 @@ +import { TaskStep } from '@cellix/serenity-framework/serenity'; +import { type Actor, Task, the } from '@serenity-js/core'; +import { OpenMemberAccountAssignment } from '../interactions/open-member-account-assignment.ts'; +import { ResolveCommunityAdministratorMembership } from '../interactions/resolve-community-administrator-membership.ts'; +import { SelectMemberEndUserAccount } from '../interactions/select-member-end-user-account.ts'; +import { SubmitMemberAccountAssignment } from '../interactions/submit-member-account-assignment.ts'; + +export const AssignMemberAccount = (communityName: string, displayName: string) => + Task.where( + the`#actor assigns end-user account "${displayName}" in "${communityName}"`, + new TaskStep('#actor assigns an end-user account through the community portal', async (actor) => { + await actor.attemptsTo(ResolveCommunityAdministratorMembership(actor, communityName), OpenMemberAccountAssignment(actor, communityName), SelectMemberEndUserAccount(actor, displayName), SubmitMemberAccountAssignment(actor)); + }), + ); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/create-member.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/create-member.ts new file mode 100644 index 000000000..a98546aeb --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/create-member.ts @@ -0,0 +1,14 @@ +import { TaskStep } from '@cellix/serenity-framework/serenity'; +import { type Actor, Task, the } from '@serenity-js/core'; +import { SubmitMemberCreateForm } from '../interactions/fill-and-submit-member-create-form.ts'; +import { FillMemberCreateForm } from '../interactions/fill-member-create-form.ts'; +import { OpenCreateMemberForm } from '../interactions/open-create-member-form.ts'; +import { ResolveCommunityAdministratorMembership } from '../interactions/resolve-community-administrator-membership.ts'; + +export const CreateMember = (communityName: string, memberName: string) => + Task.where( + the`#actor creates member "${memberName}" in "${communityName}" via UI`, + new TaskStep('#actor creates a member through the community portal', async (actor) => { + await actor.attemptsTo(ResolveCommunityAdministratorMembership(actor, communityName), OpenCreateMemberForm(actor, communityName), FillMemberCreateForm(actor, memberName), SubmitMemberCreateForm(actor, memberName)); + }), + ); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/list-members.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/list-members.ts new file mode 100644 index 000000000..11813b929 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/list-members.ts @@ -0,0 +1,12 @@ +import { TaskStep } from '@cellix/serenity-framework/serenity'; +import { type Actor, Task, the } from '@serenity-js/core'; +import { OpenCommunityMemberList } from '../interactions/open-community-member-list.ts'; +import { ResolveCommunityAdministratorMembership } from '../interactions/resolve-community-administrator-membership.ts'; + +export const ListMembers = (communityName: string) => + Task.where( + the`#actor lists members in "${communityName}" via UI`, + new TaskStep('#actor opens the community member list', async (actor) => { + await actor.attemptsTo(ResolveCommunityAdministratorMembership(actor, communityName), OpenCommunityMemberList(actor, communityName)); + }), + ); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/remove-member.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/remove-member.ts new file mode 100644 index 000000000..4ae684589 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/remove-member.ts @@ -0,0 +1,11 @@ +import { TaskStep } from '@cellix/serenity-framework/serenity'; +import { type Actor, Task, the } from '@serenity-js/core'; +import { RemoveMember as RemoveMemberInteraction } from '../interactions/remove-member.ts'; + +export const RemoveMember = (communityName: string, memberName: string) => + Task.where( + the`#actor removes member "${memberName}" from "${communityName}"`, + new TaskStep('#actor removes a member through the community portal', async (actor) => { + await actor.attemptsTo(RemoveMemberInteraction(actor, communityName, memberName)); + }), + ); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/search-member-list.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/search-member-list.ts new file mode 100644 index 000000000..79c4d8caf --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/search-member-list.ts @@ -0,0 +1,11 @@ +import { TaskStep } from '@cellix/serenity-framework/serenity'; +import { type Actor, Task, the } from '@serenity-js/core'; +import { SearchMemberList as SearchMemberListInteraction } from '../interactions/search-member-list.ts'; + +export const SearchMemberList = (searchTerm: string) => + Task.where( + the`#actor searches the member list for "${searchTerm}"`, + new TaskStep('#actor searches the open member list', async (actor) => { + await actor.attemptsTo(SearchMemberListInteraction(actor, searchTerm)); + }), + ); diff --git a/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/update-member-profile.ts b/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/update-member-profile.ts new file mode 100644 index 000000000..f20d16a98 --- /dev/null +++ b/packages/ocom-verification/e2e-tests/src/contexts/community/tasks/update-member-profile.ts @@ -0,0 +1,26 @@ +import { TaskStep } from '@cellix/serenity-framework/serenity'; +import { type Actor, Task, the } from '@serenity-js/core'; +import { SubmitMemberProfileForm } from '../interactions/fill-and-submit-member-profile-form.ts'; +import { FillMemberProfileForm } from '../interactions/fill-member-profile-form.ts'; +import { OpenMemberProfileEditor } from '../interactions/open-member-profile-editor.ts'; +import { ResolveCommunityAdministratorMembership } from '../interactions/resolve-community-administrator-membership.ts'; +import type { MemberProfileExpectation } from '../notes/member-notes.ts'; + +interface UpdateMemberProfileDetails { + communityName: string; + memberName: string; + profile: MemberProfileExpectation; +} + +export const UpdateMemberProfile = (details: UpdateMemberProfileDetails) => + Task.where( + the`#actor updates member profile for "${details.memberName}" in "${details.communityName}"`, + new TaskStep('#actor updates the member profile through the community portal', async (actor) => { + await actor.attemptsTo( + ResolveCommunityAdministratorMembership(actor, details.communityName), + OpenMemberProfileEditor(actor, details.communityName, details.memberName), + FillMemberProfileForm(actor, details.profile), + SubmitMemberProfileForm(actor), + ); + }), + ); diff --git a/packages/ocom-verification/e2e-tests/src/shared/abilities/oauth2-login.ts b/packages/ocom-verification/e2e-tests/src/shared/abilities/oauth2-login.ts index 2425aa4f9..70abd4db3 100644 --- a/packages/ocom-verification/e2e-tests/src/shared/abilities/oauth2-login.ts +++ b/packages/ocom-verification/e2e-tests/src/shared/abilities/oauth2-login.ts @@ -106,3 +106,18 @@ export const LogInWithOAuth2 = (email = actors.CommunityOwner.email, password = await OAuth2Login.as(actor as Actor).authenticate(actor as Actor, { email, password }); }) as Activity, ); + +export const SwitchOAuth2User = (email: string, password = 'password') => + Task.where( + the`#actor switches OAuth2 user`, + new TaskStep('#actor clears the current session and logs in again', async (actor) => { + const serenityActor = actor as Actor; + const { page } = BrowseTheWeb.withActor(serenityActor); + await page.evaluate(() => { + localStorage.clear(); + sessionStorage.clear(); + }); + await page.context().clearCookies(); + await OAuth2Login.as(serenityActor).authenticate(serenityActor, { email, password }); + }) as Activity, + ); diff --git a/packages/ocom-verification/verification-shared/src/pages/index.ts b/packages/ocom-verification/verification-shared/src/pages/index.ts index 92c1e1c6b..780ee5d5a 100644 --- a/packages/ocom-verification/verification-shared/src/pages/index.ts +++ b/packages/ocom-verification/verification-shared/src/pages/index.ts @@ -1,4 +1,8 @@ export { CommunityPage } from './community.page.ts'; export { HomePage } from './home.page.ts'; +export { MemberAccountsPage } from './member-accounts.page.ts'; +export { MemberCreatePage } from './member-create.page.ts'; +export { MemberListPage } from './member-list.page.ts'; +export { MemberProfilePage } from './member-profile.page.ts'; export { STAFF_ROLE_PERMISSION_LABELS, StaffRoleFormPage } from './staff-role-form.page.ts'; export { StaffRolesListPage } from './staff-roles-list.page.ts'; diff --git a/packages/ocom-verification/verification-shared/src/pages/member-accounts.page.ts b/packages/ocom-verification/verification-shared/src/pages/member-accounts.page.ts new file mode 100644 index 000000000..8db72039e --- /dev/null +++ b/packages/ocom-verification/verification-shared/src/pages/member-accounts.page.ts @@ -0,0 +1,39 @@ +import { AdapterBackedPageObject, type ElementHandle } from '@cellix/serenity-framework/pages'; + +export class MemberAccountsPage extends AdapterBackedPageObject { + get endUserSelect(): ElementHandle { + return this.adapter.getByLabel('End User'); + } + + get addMemberAccountButton(): ElementHandle { + return this.adapter.getByRole('button', { name: /Add Member Account/i }); + } + + get addAccountButton(): ElementHandle { + return this.adapter.getByRole('button', { name: /Add Account/i }); + } + + get errorToast(): ElementHandle { + return this.adapter.locator('.ant-message-error, .ant-notification-notice-error'); + } + + linkedAccountEmail(email: string): ElementHandle { + return this.adapter.getByText(email); + } + + async linkedAccountCount(email: string): Promise { + const cells = await this.adapter.locatorAll('tbody td'); + const texts = await Promise.all(cells.map((cell) => cell.textContent())); + return texts.filter((text) => text?.trim() === email).length; + } + + async selectEndUser(displayName: string): Promise { + await this.endUserSelect.click(); + await this.endUserSelect.fill(displayName); + await this.adapter.getByText(displayName, { selector: '.ant-select-item-option-content' }).click(); + } + + async clickAddMemberAccount(): Promise { + await this.addMemberAccountButton.click(); + } +} diff --git a/packages/ocom-verification/verification-shared/src/pages/member-create.page.ts b/packages/ocom-verification/verification-shared/src/pages/member-create.page.ts new file mode 100644 index 000000000..b6c1775cf --- /dev/null +++ b/packages/ocom-verification/verification-shared/src/pages/member-create.page.ts @@ -0,0 +1,27 @@ +import { AdapterBackedPageObject, type ElementHandle } from '@cellix/serenity-framework/pages'; + +export class MemberCreatePage extends AdapterBackedPageObject { + get memberNameInput(): ElementHandle { + return this.adapter.getByLabel('Member Name'); + } + + get createMemberButton(): ElementHandle { + return this.adapter.getByRole('button', { name: /Create Member/i }); + } + + get validationError(): ElementHandle { + return this.adapter.locator('.ant-form-item-explain-error'); + } + + get errorToast(): ElementHandle { + return this.adapter.locator('.ant-message-error, [role="alert"]'); + } + + async fillMemberName(value: string): Promise { + await this.memberNameInput.fill(value); + } + + async clickCreateMember(): Promise { + await this.createMemberButton.click(); + } +} diff --git a/packages/ocom-verification/verification-shared/src/pages/member-list.page.ts b/packages/ocom-verification/verification-shared/src/pages/member-list.page.ts new file mode 100644 index 000000000..59930eaa5 --- /dev/null +++ b/packages/ocom-verification/verification-shared/src/pages/member-list.page.ts @@ -0,0 +1,36 @@ +import { AdapterBackedPageObject, type ElementHandle } from '@cellix/serenity-framework/pages'; + +export class MemberListPage extends AdapterBackedPageObject { + get searchInput(): ElementHandle { + return this.adapter.getByPlaceholder('Search by member name or email'); + } + + memberName(name: string): ElementHandle { + return this.adapter.getByText(name); + } + + get errorToast(): ElementHandle { + return this.adapter.locator('.ant-message-error, .ant-notification-notice-error'); + } + + async searchByMemberName(name: string): Promise { + await this.searchInput.fill(name); + } + + async clickRemoveMember(name: string): Promise { + const row = this.adapter.getByRole('row', { name: new RegExp(name) }); + const buttons = await row.querySelectorAll('button'); + for (const button of buttons) { + if ((await button.textContent())?.trim() === 'Remove') { + await button.click(); + return; + } + } + const removeButton = this.adapter.getByRole('button', { name: /^Remove$/i }); + if (await removeButton.isVisible()) { + await removeButton.click(); + return; + } + throw new Error(`Remove action not found for member "${name}"`); + } +} diff --git a/packages/ocom-verification/verification-shared/src/pages/member-profile.page.ts b/packages/ocom-verification/verification-shared/src/pages/member-profile.page.ts new file mode 100644 index 000000000..85831d9de --- /dev/null +++ b/packages/ocom-verification/verification-shared/src/pages/member-profile.page.ts @@ -0,0 +1,127 @@ +import { AdapterBackedPageObject, type ElementHandle } from '@cellix/serenity-framework/pages'; + +export class MemberProfilePage extends AdapterBackedPageObject { + get displayNameInput(): ElementHandle { + return this.adapter.getByPlaceholder('Display Name'); + } + + get emailInput(): ElementHandle { + return this.adapter.getByPlaceholder('Email'); + } + + get bioInput(): ElementHandle { + return this.adapter.getByPlaceholder('Bio'); + } + + get editProfileButton(): ElementHandle { + return this.adapter.getByRole('button', { name: /Edit Profile/i }); + } + + get saveProfileButton(): ElementHandle { + return this.adapter.getByRole('button', { name: /Save Profile/i }); + } + + get firstValidationError(): ElementHandle { + return this.adapter.locator('.ant-form-item-explain-error'); + } + + get errorToast(): ElementHandle { + return this.adapter.locator('.ant-message-error, [role="alert"]'); + } + + async clickEditProfile(): Promise { + await this.editProfileButton.click(); + } + + async clickSaveProfile(): Promise { + await this.saveProfileButton.click(); + } + + async fillDisplayName(value: string): Promise { + await this.displayNameInput.fill(value); + } + + async fillEmail(value: string): Promise { + await this.emailInput.fill(value); + } + + async fillBio(value: string): Promise { + await this.bioInput.fill(value); + } + + async displayNameValue(): Promise { + return (await this.displayNameInput.inputValue()) ?? ''; + } + + async emailValue(): Promise { + return (await this.emailInput.inputValue()) ?? ''; + } + + async bioValue(): Promise { + return (await this.bioInput.inputValue()) ?? ''; + } + + async setShowInterests(value: boolean): Promise { + await this.setSwitchAtIndex(0, value); + } + + async setShowEmail(value: boolean): Promise { + await this.setSwitchAtIndex(1, value); + } + + async setShowProfile(value: boolean): Promise { + await this.setSwitchAtIndex(2, value); + } + + async setShowLocation(value: boolean): Promise { + await this.setSwitchAtIndex(3, value); + } + + async setShowProperties(value: boolean): Promise { + await this.setSwitchAtIndex(4, value); + } + + async showInterestsValue(): Promise { + return await this.switchValueAtIndex(0); + } + + async showEmailValue(): Promise { + return await this.switchValueAtIndex(1); + } + + async showProfileValue(): Promise { + return await this.switchValueAtIndex(2); + } + + async showLocationValue(): Promise { + return await this.switchValueAtIndex(3); + } + + async showPropertiesValue(): Promise { + return await this.switchValueAtIndex(4); + } + + private async setSwitchAtIndex(index: number, expectedChecked: boolean): Promise { + const switches = await this.adapter.locatorAll('button[role="switch"]'); + const target = switches[index]; + if (!target) { + throw new Error(`Expected switch at index ${index} but none was found`); + } + + const checkedState = await target.getAttribute('aria-checked'); + const isChecked = checkedState === 'true'; + if (isChecked !== expectedChecked) { + await target.click(); + } + } + + private async switchValueAtIndex(index: number): Promise { + const switches = await this.adapter.locatorAll('button[role="switch"]'); + const target = switches[index]; + if (!target) { + throw new Error(`Expected switch at index ${index} but none was found`); + } + + return (await target.getAttribute('aria-checked')) === 'true'; + } +} diff --git a/packages/ocom-verification/verification-shared/src/scenarios/community/member/member-lifecycle.feature b/packages/ocom-verification/verification-shared/src/scenarios/community/member/member-lifecycle.feature new file mode 100644 index 000000000..3b2a3a174 --- /dev/null +++ b/packages/ocom-verification/verification-shared/src/scenarios/community/member/member-lifecycle.feature @@ -0,0 +1,115 @@ +Feature: Community member management + + As a community owner or administrator + I want to manage members within a specific community + So that member records and account access remain accurate and correctly scoped + + Background: + Given Alice is signed in as a community owner for member management + And Alice has a community named "Green Oaks" + And Alice has a community named "Blue Harbor" + + Scenario: Create a member record in a community + When Alice creates a member in "Green Oaks" with: + | memberName | Charlie Walker | + Then the member should be created successfully in "Green Oaks" + + Scenario: Update all member profile fields within a community + Given Alice creates a member in "Green Oaks" with: + | memberName | Charlie Walker | + When Alice updates member "Charlie Walker" in "Green Oaks" with: + | name | Charles Walker | + | email | charles.walker@example.com | + | bio | Community gardener and volunteer | + | avatarDocumentId | avatar-charles-001 | + | interests | gardening,reading,volunteering | + | showInterests | true | + | showEmail | true | + | showProfile | true | + | showLocation | false | + | showProperties | true | + Then the member should be updated successfully in "Green Oaks" + + Scenario: Assign a community end-user account to a member + Given Alice creates a member in "Green Oaks" with: + | memberName | Charlie Walker | + And end-user account "Charlie" is available for assignment in "Green Oaks" + When Alice associates end-user account "Charlie" to member "Charlie Walker" in "Green Oaks" + Then member "Charlie Walker" should be linked to end-user account "Charlie" + + @api-only + Scenario: Update a member role with a role from the same community + Given Alice creates a member in "Green Oaks" with: + | memberName | Charlie Walker | + And a role "board member" exists in "Green Oaks" + When Alice changes member "Charlie Walker" in "Green Oaks" to role "board member" + Then member "Charlie Walker" should have role "board member" in "Green Oaks" + + @api-only @validation + Scenario: Cannot assign a role from another community + Given Alice creates a member in "Green Oaks" with: + | memberName | Charlie Walker | + And a role "harbor board member" exists in "Blue Harbor" + When Alice attempts to change member "Charlie Walker" in "Green Oaks" to role "harbor board member" + Then she should see a member error for "role" + And member "Charlie Walker" should not have role "harbor board member" in "Green Oaks" + + Scenario: List members as a community administrator + Given Bob is an authenticated community admin for "Green Oaks" + And the following members exist in "Green Oaks": + | memberName | + | Charlie Walker | + | Dana Ortiz | + And Alice creates a member in "Blue Harbor" with: + | memberName | Erin Lawson | + When Bob lists members for "Green Oaks" + Then Bob should see the following members in "Green Oaks": + | memberName | + | Charlie Walker | + | Dana Ortiz | + And Bob should not see member "Erin Lawson" from "Blue Harbor" + + Scenario: Filter the community member list by member name + Given the following members exist in "Green Oaks": + | memberName | + | Charlie Walker | + | Dana Ortiz | + | Charlotte Webb | + When Alice searches the member list in "Green Oaks" for "Charlie" + Then Alice should see the following members in "Green Oaks": + | memberName | + | Charlie Walker | + And Alice should not see member "Dana Ortiz" in the filtered results + + Scenario: Remove a member from a community + Given Alice creates a member in "Green Oaks" with: + | memberName | Charlie Walker | + When Alice removes member "Charlie Walker" from "Green Oaks" + Then the member should be removed successfully from "Green Oaks" + And member "Charlie Walker" should not appear in member listings for "Green Oaks" + + @validation + Scenario: Cannot create a member without a required name + When Alice attempts to create a member in "Green Oaks" with: + | memberName | | + Then she should see a member error for "memberName" + And no new member should be created in "Green Oaks" + + @validation + Scenario: Cannot associate the same end-user account twice to the same member + Given Alice creates a member in "Green Oaks" with: + | memberName | Charlie Walker | + And end-user account "Charlie" is available for assignment in "Green Oaks" + And member "Charlie Walker" is already linked to end-user account "Charlie" + When Alice associates end-user account "Charlie" to member "Charlie Walker" in "Green Oaks" + Then she should see a member error for "accountAssociation" + And member "Charlie Walker" should remain linked to end-user account "Charlie" only once + + @authorization + Scenario: An end user without community membership cannot remove a member + Given Alice creates a member in "Green Oaks" with: + | memberName | Charlie Walker | + And Evan is signed in without membership in "Green Oaks" + When Evan attempts to remove member "Charlie Walker" from "Green Oaks" + Then Evan should receive an authorization error for member management + And member "Charlie Walker" should remain in "Green Oaks" \ No newline at end of file diff --git a/packages/ocom-verification/verification-shared/src/test-data/index.ts b/packages/ocom-verification/verification-shared/src/test-data/index.ts index b4a279858..bb60dea82 100644 --- a/packages/ocom-verification/verification-shared/src/test-data/index.ts +++ b/packages/ocom-verification/verification-shared/src/test-data/index.ts @@ -1,6 +1,7 @@ export { DEFAULT_STAFF_ROLE_NAMES, END_USER_IDS, + type EndUserRoleSeedDetails, type EndUserSeedDocument, endUsers, type MongoDBSeedContext, @@ -10,9 +11,11 @@ export { type StaffRoleSeedDocument, type StaffUserSeedDocument, seedDatabase, + seedEndUserRole, staffRoles, staffUsers, } from './seed/index.ts'; + export { actors, defaultActor, diff --git a/packages/ocom-verification/verification-shared/src/test-data/seed/index.ts b/packages/ocom-verification/verification-shared/src/test-data/seed/index.ts index f6d65410b..e1203b7ab 100644 --- a/packages/ocom-verification/verification-shared/src/test-data/seed/index.ts +++ b/packages/ocom-verification/verification-shared/src/test-data/seed/index.ts @@ -1,4 +1,4 @@ export { END_USER_IDS, type EndUserSeedDocument, endUsers } from './end-users.ts'; -export { type MongoDBSeedContext, type MongoDBSeedDataFunction, seedDatabase } from './seed.ts'; +export { type EndUserRoleSeedDetails, type MongoDBSeedContext, type MongoDBSeedDataFunction, seedDatabase, seedEndUserRole } from './seed.ts'; export { DEFAULT_STAFF_ROLE_NAMES, STAFF_ROLE_IDS, type StaffRoleSeedDocument, staffRoles } from './staff-roles.ts'; export { STAFF_USER_IDS, type StaffUserSeedDocument, staffUsers } from './staff-users.ts'; diff --git a/packages/ocom-verification/verification-shared/src/test-data/seed/seed.ts b/packages/ocom-verification/verification-shared/src/test-data/seed/seed.ts index 3845a3a33..a1b2f9f3b 100644 --- a/packages/ocom-verification/verification-shared/src/test-data/seed/seed.ts +++ b/packages/ocom-verification/verification-shared/src/test-data/seed/seed.ts @@ -10,6 +10,11 @@ export interface MongoDBSeedContext { export type MongoDBSeedDataFunction = (context: MongoDBSeedContext) => Promise; +export interface EndUserRoleSeedDetails { + communityId: string; + roleName: string; +} + function toObjectId(id: string): ObjectId { return new ObjectId(id); } @@ -53,3 +58,42 @@ export async function seedDatabase(context: MongoDBSeedContext): Promise { await client.close(); } } + +export async function seedEndUserRole(context: MongoDBSeedContext, details: EndUserRoleSeedDetails): Promise { + const client = new MongoClient(context.connectionString); + const roleId = new ObjectId(); + const timestamp = new Date(); + try { + await client.connect(); + await client + .db(context.dbName) + .collection('roles') + .insertOne({ + _id: roleId, + roleType: 'end-user-roles', + community: toObjectId(details.communityId), + roleName: details.roleName, + isDefault: false, + permissions: { + servicePermissions: { canManageServices: false }, + serviceTicketPermissions: { canCreateTickets: false, canManageTickets: false, canAssignTickets: false, canWorkOnTickets: false }, + violationTicketPermissions: { canCreateTickets: false, canManageTickets: false, canAssignTickets: false, canWorkOnTickets: false }, + communityPermissions: { + canManageRolesAndPermissions: false, + canManageCommunitySettings: false, + canManageSiteContent: false, + canManageMembers: false, + canEditOwnMemberProfile: false, + canEditOwnMemberAccounts: false, + }, + propertyPermissions: { canManageProperties: false, canEditOwnProperty: false }, + }, + schemaVersion: '1.0.0', + createdAt: timestamp, + updatedAt: timestamp, + }); + return roleId.toHexString(); + } finally { + await client.close(); + } +} diff --git a/packages/ocom/service-otel/package.json b/packages/ocom/service-otel/package.json index 18fb61910..0dc45ff5e 100644 --- a/packages/ocom/service-otel/package.json +++ b/packages/ocom/service-otel/package.json @@ -26,17 +26,18 @@ }, "dependencies": { "@azure/functions-opentelemetry-instrumentation": "0.1.0", - "@azure/monitor-opentelemetry-exporter": "1.0.0-beta.31", + "@azure/monitor-opentelemetry-exporter": "1.0.0-beta.43", "@cellix/api-services-spec": "workspace:*", "@opentelemetry/api": "1.9.0", "@opentelemetry/instrumentation-dataloader": "0.17.0", "@opentelemetry/instrumentation-graphql": "0.48.0", - "@opentelemetry/instrumentation-http": "0.52.1", + "@opentelemetry/instrumentation-http": "0.220.0", "@opentelemetry/instrumentation-mongoose": "0.47.0", - "@opentelemetry/sdk-logs": "0.57.2", - "@opentelemetry/sdk-metrics": "1.30.1", - "@opentelemetry/sdk-node": "0.57.2", - "@opentelemetry/sdk-trace-node": "1.30.1", + "@opentelemetry/sdk-logs": "0.220.0", + "@opentelemetry/sdk-metrics": "2.9.0", + "@opentelemetry/sdk-node": "0.220.0", + "@opentelemetry/sdk-trace-node": "2.9.0", + "@opentelemetry/resources": "2.9.0", "@opentelemetry/semantic-conventions": "1.28.0" }, "devDependencies": { diff --git a/packages/ocom/service-otel/src/index.test.ts b/packages/ocom/service-otel/src/index.test.ts index 0b7eed41c..1cfaf6571 100644 --- a/packages/ocom/service-otel/src/index.test.ts +++ b/packages/ocom/service-otel/src/index.test.ts @@ -5,20 +5,23 @@ import { expect, vi } from 'vitest'; import { ServiceOtel } from './index.ts'; const test = { for: describeFeature }; -vi.mock('@opentelemetry/sdk-node', () => { - // Mock Resource class and resources namespace +vi.mock('@opentelemetry/resources', () => { class Resource { private attributes: Record; constructor(attrs: Record) { this.attributes = attrs; } - static default() { - return new Resource({ default: true }); - } merge(other: Resource) { return new Resource({ ...this.attributes, ...other.attributes }); } } + return { + defaultResource: () => new Resource({ default: true }), + resourceFromAttributes: (attributes: Record) => new Resource(attributes), + }; +}); + +vi.mock('@opentelemetry/sdk-node', () => { // Mock NodeSDK and track config let lastConfig: unknown; class NodeSDK { @@ -33,7 +36,6 @@ vi.mock('@opentelemetry/sdk-node', () => { } return { NodeSDK, - resources: { Resource }, }; }); diff --git a/packages/ocom/service-otel/src/index.ts b/packages/ocom/service-otel/src/index.ts index 4a456eae5..fa8389a95 100644 --- a/packages/ocom/service-otel/src/index.ts +++ b/packages/ocom/service-otel/src/index.ts @@ -1,4 +1,5 @@ import type { SyncServiceBase } from '@cellix/api-services-spec'; +import { defaultResource, resourceFromAttributes } from '@opentelemetry/resources'; import * as opentelemetry from '@opentelemetry/sdk-node'; import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions'; import { OtelBuilder } from './otel-builder.ts'; @@ -30,8 +31,8 @@ export class ServiceOtel implements SyncServiceBase { metricReader: metricReader, instrumentations: instrumentations, - resource: opentelemetry.resources.Resource.default().merge( - new opentelemetry.resources.Resource({ + resource: defaultResource().merge( + resourceFromAttributes({ [ATTR_SERVICE_NAME]: 'Cellix Demo', [ATTR_SERVICE_VERSION]: '1.0.0', }), diff --git a/packages/ocom/service-otel/src/otel-builder.ts b/packages/ocom/service-otel/src/otel-builder.ts index cd10147dc..e32ee943a 100644 --- a/packages/ocom/service-otel/src/otel-builder.ts +++ b/packages/ocom/service-otel/src/otel-builder.ts @@ -1,16 +1,16 @@ -import type { NodeSDKConfiguration } from '@opentelemetry/sdk-node'; -import { AzureMonitorTraceExporter, AzureMonitorMetricExporter, AzureMonitorLogExporter } from '@azure/monitor-opentelemetry-exporter'; -import { BatchLogRecordProcessor, SimpleLogRecordProcessor, ConsoleLogRecordExporter } from '@opentelemetry/sdk-logs'; -import { BatchSpanProcessor, SimpleSpanProcessor, ConsoleSpanExporter, type Sampler, SamplingDecision, ParentBasedSampler, AlwaysOnSampler } from '@opentelemetry/sdk-trace-node'; -import { PeriodicExportingMetricReader, ConsoleMetricExporter } from '@opentelemetry/sdk-metrics'; -import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; +import azureOtel from '@azure/functions-opentelemetry-instrumentation'; +import { AzureMonitorLogExporter, AzureMonitorMetricExporter, AzureMonitorTraceExporter } from '@azure/monitor-opentelemetry-exporter'; +import type { Attributes, Context, Link, SpanKind } from '@opentelemetry/api'; import { DataloaderInstrumentation } from '@opentelemetry/instrumentation-dataloader'; import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql'; -import azureOtel from '@azure/functions-opentelemetry-instrumentation'; +import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; import { MongooseInstrumentation } from '@opentelemetry/instrumentation-mongoose'; - +import { BatchLogRecordProcessor, ConsoleLogRecordExporter, SimpleLogRecordProcessor } from '@opentelemetry/sdk-logs'; +import { ConsoleMetricExporter, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'; +import type { NodeSDKConfiguration } from '@opentelemetry/sdk-node'; +import { AlwaysOnSampler, BatchSpanProcessor, ConsoleSpanExporter, ParentBasedSampler, type Sampler, SamplingDecision, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'; import { httpInstrumentationConfig } from './http-config.ts'; -import type { Attributes, Context, Link, SpanKind } from '@opentelemetry/api'; + const { AzureFunctionsInstrumentation } = azureOtel; //Need to use destructuring to access AzureFunctionsInstrumentation (CommonJS module) interface Exporters { @@ -56,7 +56,7 @@ export class OtelBuilder { if (useSimpleProcessors) { return { spanProcessors: [new SimpleSpanProcessor(exporters.traceExporter)], - logRecordProcessors: [new SimpleLogRecordProcessor(exporters.logExporter)], + logRecordProcessors: [new SimpleLogRecordProcessor({ exporter: exporters.logExporter })], }; } else { const EXPORT_TIMEOUT_MILLIS = 15000; @@ -69,7 +69,8 @@ export class OtelBuilder { }), ], logRecordProcessors: [ - new BatchLogRecordProcessor(exporters.logExporter, { + new BatchLogRecordProcessor({ + exporter: exporters.logExporter, exportTimeoutMillis: EXPORT_TIMEOUT_MILLIS, maxQueueSize: MAX_QUEUE_SIZE, }), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9c1b08443..d440d4a84 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -70,8 +70,8 @@ catalogs: specifier: 7.0.0-dev.20260428.1 version: 7.0.0-dev.20260428.1 '@vitest/coverage-istanbul': - specifier: 4.1.8 - version: 4.1.8 + specifier: 4.1.10 + version: 4.1.10 antd: specifier: 6.3.5 version: 6.3.5 @@ -118,14 +118,14 @@ catalogs: specifier: ^0.28.0 version: 0.28.0 vitest: - specifier: 4.1.8 - version: 4.1.8 + specifier: 4.1.10 + version: 4.1.10 overrides: - '@vitest/browser': 4.1.8 - '@vitest/browser-playwright': 4.1.8 + '@vitest/browser': 4.1.10 + '@vitest/browser-playwright': 4.1.10 happy-dom: 20.10.1 - axios: 1.16.0 + axios: 1.18.0 body-parser: 2.3.0 esbuild: 0.28.1 follow-redirects: ^1.16.0 @@ -140,7 +140,7 @@ overrides: serve-handler>minimatch: 3.1.5 serialize-javascript@6.0.2: 7.0.5 serialize-javascript@7.0.4: 7.0.5 - svgo: ^3.3.3 + svgo: ^3.3.4 yaml@2.8.2: 2.8.3 yauzl@3.2.0: 3.2.1 qs: 6.15.2 @@ -160,10 +160,10 @@ overrides: ws@8.20.0: 8.21.0 playwright-core: 1.59.0 playwright: 1.59.0 - postcss: 8.5.10 + postcss: 8.5.12 protobufjs: 7.6.5 ip-address: ^10.1.1 - fast-uri: ^4.0.1 + fast-uri: ^4.1.1 '@babel/plugin-transform-modules-systemjs': 7.29.4 '@babel/core': ^7.29.6 js-yaml: 4.3.0 @@ -171,7 +171,8 @@ overrides: shell-quote@<1.8.4: 1.8.4 '@opentelemetry/exporter-prometheus@0.57.2': 0.217.0 '@opentelemetry/core@2.7.1': 2.8.0 - ws: 8.21.0 + ws: 8.21.1 + websocket-driver: 0.7.5 shell-quote: 1.9.0 '@grpc/grpc-js': '>=1.14.4' form-data: ^4.0.6 @@ -200,7 +201,7 @@ importers: devDependencies: '@amiceli/vitest-cucumber': specifier: ^6.3.0 - version: 6.3.0(vitest@4.1.8) + version: 6.3.0(vitest@4.1.10) '@ant-design/cli': specifier: ^6.3.5 version: 6.3.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) @@ -236,7 +237,7 @@ importers: version: 1.59.0 '@sonar/scan': specifier: ^4.3.0 - version: 4.3.2 + version: 4.3.2(supports-color@8.1.1) '@types/node': specifier: 'catalog:' version: 22.19.15 @@ -245,7 +246,7 @@ importers: version: 7.0.0-dev.20260428.1 '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(supports-color@8.1.1)(vitest@4.1.8) + version: 4.1.10(supports-color@8.1.1)(vitest@4.1.10) chrome-devtools-mcp: specifier: ^1.3.0 version: 1.3.0 @@ -278,7 +279,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) apps/api: dependencies: @@ -351,7 +352,7 @@ importers: version: link:../../packages/ocom/local-dev-config '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) archunit: specifier: 'catalog:' version: 2.1.63 @@ -369,7 +370,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) apps/docs: dependencies: @@ -433,7 +434,7 @@ importers: version: 6.0.1(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) jsdom: specifier: ^26.1.0 version: 26.1.0 @@ -442,7 +443,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) apps/server-mongodb-memory-mock: dependencies: @@ -498,7 +499,7 @@ importers: version: link:../../packages/cellix/local-dev '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -507,13 +508,13 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) apps/ui-community: dependencies: '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@cellix/ui-core': specifier: workspace:* version: link:../../packages/cellix/ui-core @@ -543,7 +544,7 @@ importers: version: 6.3.5(luxon@3.7.2)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) apollo-link-rest: specifier: ^0.9.0 - version: 0.9.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(qs@6.15.2) + version: 0.9.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(qs@6.15.2) less: specifier: ^4.4.0 version: 4.4.2 @@ -583,7 +584,7 @@ importers: version: 10.4.2(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) '@storybook/addon-vitest': specifier: 'catalog:' - version: 10.4.2(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8))(@vitest/runner@4.1.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.8) + version: 10.4.2(@vitest/browser-playwright@4.1.10)(@vitest/browser@4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10))(@vitest/runner@4.1.10)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.10) '@storybook/react': specifier: 10.4.2 version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@6.0.3) @@ -601,7 +602,7 @@ importers: version: 6.0.1(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) esbuild: specifier: 0.28.1 version: 0.28.1 @@ -616,7 +617,7 @@ importers: version: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) storybook-addon-apollo-client: specifier: ^9.0.0 - version: 9.0.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(react@19.2.0) + version: 9.0.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(react@19.2.0) tailwindcss: specifier: ^3.4.17 version: 3.4.18(tsx@4.21.0)(yaml@2.8.3) @@ -631,13 +632,13 @@ importers: version: 0.28.0(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) apps/ui-staff: dependencies: '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@cellix/ui-core': specifier: workspace:* version: link:../../packages/cellix/ui-core @@ -676,7 +677,7 @@ importers: version: 6.3.5(luxon@3.7.2)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) apollo-link-rest: specifier: ^0.9.0 - version: 0.9.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(qs@6.15.2) + version: 0.9.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(qs@6.15.2) less: specifier: ^4.4.0 version: 4.4.2 @@ -713,7 +714,7 @@ importers: version: 6.0.1(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) esbuild: specifier: 0.28.1 version: 0.28.1 @@ -737,7 +738,7 @@ importers: version: 0.28.0(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/cellix/api-services-spec: devDependencies: @@ -773,7 +774,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/cellix/config-rolldown: devDependencies: @@ -785,7 +786,7 @@ importers: version: link:../config-vitest '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -797,7 +798,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/cellix/config-typescript: {} @@ -808,16 +809,16 @@ importers: version: link:../config-typescript '@storybook/addon-vitest': specifier: 'catalog:' - version: 10.4.2(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8))(@vitest/runner@4.1.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.8) + version: 10.4.2(@vitest/browser-playwright@4.1.10)(@vitest/browser@4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10))(@vitest/runner@4.1.10)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.10) '@vitest/browser-playwright': - specifier: 4.1.8 - version: 4.1.8(playwright@1.59.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8) + specifier: 4.1.10 + version: 4.1.10(playwright@1.59.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10) typescript: specifier: 'catalog:' version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/cellix/domain-seedwork: devDependencies: @@ -829,7 +830,7 @@ importers: version: link:../config-vitest '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -838,7 +839,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/cellix/event-bus-seedwork-node: dependencies: @@ -857,7 +858,7 @@ importers: version: link:../config-vitest '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -888,7 +889,7 @@ importers: devDependencies: '@amiceli/vitest-cucumber': specifier: ^6.3.0 - version: 6.3.0(vitest@4.1.8) + version: 6.3.0(vitest@4.1.10) '@cellix/config-typescript': specifier: workspace:* version: link:../config-typescript @@ -897,7 +898,7 @@ importers: version: link:../config-vitest '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -906,7 +907,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/cellix/graphql-core: dependencies: @@ -925,7 +926,7 @@ importers: version: link:../config-vitest '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -934,7 +935,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/cellix/local-dev: devDependencies: @@ -949,7 +950,7 @@ importers: version: 22.19.15 '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -958,7 +959,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/cellix/mongoose-seedwork: dependencies: @@ -977,7 +978,7 @@ importers: version: link:../config-vitest '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) mongodb: specifier: 'catalog:' version: 6.18.0 @@ -995,7 +996,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/cellix/serenity-framework: dependencies: @@ -1050,7 +1051,7 @@ importers: version: 19.2.7 '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) playwright: specifier: 1.59.0 version: 1.59.0 @@ -1065,7 +1066,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/cellix/server-mongodb-memory-mock-seedwork: dependencies: @@ -1115,7 +1116,7 @@ importers: version: 5.0.5 '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -1124,7 +1125,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/cellix/service-blob-storage: dependencies: @@ -1146,7 +1147,7 @@ importers: version: link:../config-vitest '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -1155,7 +1156,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/cellix/service-queue-storage: dependencies: @@ -1180,7 +1181,7 @@ importers: devDependencies: '@amiceli/vitest-cucumber': specifier: ^6.3.0 - version: 6.3.0(vitest@4.1.8) + version: 6.3.0(vitest@4.1.10) '@cellix/config-typescript': specifier: workspace:* version: link:../config-typescript @@ -1189,7 +1190,7 @@ importers: version: link:../config-vitest '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) execa: specifier: ^9.6.0 version: 9.6.1 @@ -1201,7 +1202,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/cellix/ui-core: dependencies: @@ -1235,7 +1236,7 @@ importers: version: 10.4.2(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) '@storybook/addon-vitest': specifier: 'catalog:' - version: 10.4.2(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8))(@vitest/runner@4.1.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.8) + version: 10.4.2(@vitest/browser-playwright@4.1.10)(@vitest/browser@4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10))(@vitest/runner@4.1.10)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.10) '@storybook/react': specifier: 10.4.2 version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@6.0.3) @@ -1252,14 +1253,14 @@ importers: specifier: ^19.1.6 version: 19.2.3(@types/react@19.2.7) '@vitest/browser': - specifier: 4.1.8 - version: 4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8) + specifier: 4.1.10 + version: 4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10) '@vitest/browser-playwright': - specifier: 4.1.8 - version: 4.1.8(playwright@1.59.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8) + specifier: 4.1.10 + version: 4.1.10(playwright@1.59.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10) '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) jsdom: specifier: 'catalog:' version: 26.1.0 @@ -1280,7 +1281,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom-verification/acceptance-api: dependencies: @@ -1336,6 +1337,9 @@ importers: '@ocom/data-sources-mongoose-models': specifier: workspace:* version: link:../../ocom/data-sources-mongoose-models + '@ocom/event-handler': + specifier: workspace:* + version: link:../../ocom/event-handler '@ocom/graphql': specifier: workspace:* version: link:../../ocom/graphql @@ -1380,7 +1384,7 @@ importers: dependencies: '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@cellix/serenity-framework': specifier: workspace:* version: link:../../cellix/serenity-framework @@ -1471,7 +1475,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom-verification/e2e-tests: dependencies: @@ -1585,7 +1589,7 @@ importers: version: link:../../ocom-verification/archunit-tests '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -1594,7 +1598,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/context-spec: dependencies: @@ -1653,7 +1657,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/domain: dependencies: @@ -1705,7 +1709,7 @@ importers: version: 3.43.0 '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -1714,7 +1718,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/event-handler: dependencies: @@ -1767,7 +1771,7 @@ importers: version: link:../../ocom-verification/archunit-tests '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -1776,7 +1780,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/graphql-handler: dependencies: @@ -1810,7 +1814,7 @@ importers: version: link:../../cellix/config-vitest '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -1819,7 +1823,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/local-dev-config: dependencies: @@ -1838,7 +1842,7 @@ importers: version: 22.19.15 '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -1847,7 +1851,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/persistence: dependencies: @@ -1887,7 +1891,7 @@ importers: version: link:../../ocom-verification/archunit-tests '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -1896,7 +1900,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/rest: dependencies: @@ -1949,7 +1953,7 @@ importers: version: 1.1.6 '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -1958,7 +1962,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/service-blob-storage: dependencies: @@ -1974,7 +1978,7 @@ importers: version: link:../../cellix/config-vitest '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -1983,7 +1987,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/service-mongoose: dependencies: @@ -2005,7 +2009,7 @@ importers: version: link:../../cellix/config-vitest '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -2019,8 +2023,8 @@ importers: specifier: 0.1.0 version: 0.1.0(@opentelemetry/api@1.9.0) '@azure/monitor-opentelemetry-exporter': - specifier: 1.0.0-beta.31 - version: 1.0.0-beta.31 + specifier: 1.0.0-beta.43 + version: 1.0.0-beta.43 '@cellix/api-services-spec': specifier: workspace:* version: link:../../cellix/api-services-spec @@ -2034,23 +2038,26 @@ importers: specifier: 0.48.0 version: 0.48.0(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation-http': - specifier: 0.52.1 - version: 0.52.1(@opentelemetry/api@1.9.0) + specifier: 0.220.0 + version: 0.220.0(@opentelemetry/api@1.9.0)(supports-color@8.1.1) '@opentelemetry/instrumentation-mongoose': specifier: 0.47.0 version: 0.47.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': + specifier: 2.9.0 + version: 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-logs': - specifier: 0.57.2 - version: 0.57.2(@opentelemetry/api@1.9.0) + specifier: 0.220.0 + version: 0.220.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-metrics': - specifier: 1.30.1 - version: 1.30.1(@opentelemetry/api@1.9.0) + specifier: 2.9.0 + version: 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-node': - specifier: 0.57.2 - version: 0.57.2(@opentelemetry/api@1.9.0) + specifier: 0.220.0 + version: 0.220.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-node': - specifier: 1.30.1 - version: 1.30.1(@opentelemetry/api@1.9.0) + specifier: 2.9.0 + version: 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': specifier: 1.28.0 version: 1.28.0 @@ -2063,7 +2070,7 @@ importers: version: link:../../cellix/config-vitest '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -2072,7 +2079,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/service-queue-storage: dependencies: @@ -2088,7 +2095,7 @@ importers: version: link:../../cellix/config-vitest '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -2097,7 +2104,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/service-token-validation: dependencies: @@ -2116,7 +2123,7 @@ importers: version: link:../../cellix/config-vitest '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) rimraf: specifier: 'catalog:' version: 6.0.1 @@ -2125,7 +2132,7 @@ importers: version: 6.0.3 vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/ui-community-route-accounts: dependencies: @@ -2137,7 +2144,7 @@ importers: version: 7.22.7(antd@6.3.5(luxon@3.7.2)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@cellix/ui-core': specifier: workspace:* version: link:../../cellix/ui-core @@ -2192,7 +2199,7 @@ importers: version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(esbuild@0.28.1)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(webpack@5.105.4(esbuild@0.28.1)) '@storybook/addon-vitest': specifier: 'catalog:' - version: 10.4.2(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8))(@vitest/runner@4.1.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.8) + version: 10.4.2(@vitest/browser-playwright@4.1.10)(@vitest/browser@4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10))(@vitest/runner@4.1.10)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.10) '@storybook/react': specifier: 10.4.2 version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@6.0.3) @@ -2219,7 +2226,7 @@ importers: version: 8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/ui-community-route-admin: dependencies: @@ -2231,7 +2238,7 @@ importers: version: 7.22.7(antd@6.3.5(luxon@3.7.2)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@cellix/ui-core': specifier: workspace:* version: link:../../cellix/ui-core @@ -2286,7 +2293,7 @@ importers: version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(esbuild@0.28.1)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(webpack@5.105.4(esbuild@0.28.1)) '@storybook/addon-vitest': specifier: 'catalog:' - version: 10.4.2(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8))(@vitest/runner@4.1.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.8) + version: 10.4.2(@vitest/browser-playwright@4.1.10)(@vitest/browser@4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10))(@vitest/runner@4.1.10)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.10) '@storybook/react': specifier: ^10.4.2 version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@6.0.3) @@ -2313,7 +2320,7 @@ importers: version: 8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/ui-community-route-root: dependencies: @@ -2356,7 +2363,7 @@ importers: version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(esbuild@0.28.1)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(webpack@5.105.4(esbuild@0.28.1)) '@storybook/addon-vitest': specifier: 'catalog:' - version: 10.4.2(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8))(@vitest/runner@4.1.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.8) + version: 10.4.2(@vitest/browser-playwright@4.1.10)(@vitest/browser@4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10))(@vitest/runner@4.1.10)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.10) '@storybook/react': specifier: 'catalog:' version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@6.0.3) @@ -2383,13 +2390,13 @@ importers: version: 8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/ui-community-shared: dependencies: '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@cellix/ui-core': specifier: workspace:* version: link:../../cellix/ui-core @@ -2435,7 +2442,7 @@ importers: version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(esbuild@0.28.1)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(webpack@5.105.4(esbuild@0.28.1)) '@storybook/addon-vitest': specifier: 'catalog:' - version: 10.4.2(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8))(@vitest/runner@4.1.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.8) + version: 10.4.2(@vitest/browser-playwright@4.1.10)(@vitest/browser@4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10))(@vitest/runner@4.1.10)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.10) '@storybook/react': specifier: 'catalog:' version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@6.0.3) @@ -2462,7 +2469,7 @@ importers: version: 8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/ui-shared: dependencies: @@ -2471,7 +2478,7 @@ importers: version: 6.1.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@cellix/ui-core': specifier: workspace:* version: link:../../cellix/ui-core @@ -2520,7 +2527,7 @@ importers: version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(esbuild@0.28.1)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(webpack@5.105.4(esbuild@0.28.1)) '@storybook/addon-vitest': specifier: 'catalog:' - version: 10.4.2(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8))(@vitest/runner@4.1.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.8) + version: 10.4.2(@vitest/browser-playwright@4.1.10)(@vitest/browser@4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10))(@vitest/runner@4.1.10)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.10) '@storybook/react': specifier: 'catalog:' version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@6.0.3) @@ -2534,11 +2541,11 @@ importers: specifier: ^19.1.6 version: 19.2.3(@types/react@19.2.7) '@vitest/browser': - specifier: 4.1.8 - version: 4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8) + specifier: 4.1.10 + version: 4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10) '@vitest/coverage-istanbul': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.10(vitest@4.1.10) jsdom: specifier: 'catalog:' version: 26.1.0 @@ -2550,7 +2557,7 @@ importers: version: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) storybook-addon-apollo-client: specifier: ^9.0.0 - version: 9.0.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(react@19.2.0) + version: 9.0.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(react@19.2.0) typescript: specifier: 'catalog:' version: 6.0.3 @@ -2559,7 +2566,7 @@ importers: version: 8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/ui-staff-route-community-management: dependencies: @@ -2602,7 +2609,7 @@ importers: version: 8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/ui-staff-route-finance: dependencies: @@ -2645,7 +2652,7 @@ importers: version: 8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/ui-staff-route-root: dependencies: @@ -2688,7 +2695,7 @@ importers: version: 8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/ui-staff-route-tech-admin: dependencies: @@ -2731,7 +2738,7 @@ importers: version: 8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/ui-staff-route-user-management: dependencies: @@ -2740,7 +2747,7 @@ importers: version: 6.1.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@graphql-typed-document-node/core': specifier: ^3.2.0 version: 3.2.0(graphql@16.12.0) @@ -2777,7 +2784,7 @@ importers: version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(esbuild@0.28.1)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(webpack@5.105.4(esbuild@0.28.1)) '@storybook/addon-vitest': specifier: 'catalog:' - version: 10.4.2(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8))(@vitest/runner@4.1.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.8) + version: 10.4.2(@vitest/browser-playwright@4.1.10)(@vitest/browser@4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10))(@vitest/runner@4.1.10)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.10) '@storybook/react': specifier: 'catalog:' version: 10.4.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@6.0.3) @@ -2804,7 +2811,7 @@ importers: version: 8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ocom/ui-staff-shared: dependencies: @@ -2813,7 +2820,7 @@ importers: version: 6.1.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@apollo/client': specifier: ^3.13.9 - version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@cellix/ui-core': specifier: workspace:* version: link:../../cellix/ui-core @@ -2865,7 +2872,7 @@ importers: version: 8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages: @@ -3176,6 +3183,10 @@ packages: resolution: {integrity: sha512-EHaOXW0RYDKS5CFffnixdyRPak5ytiCtU7uXDcP/uiY+A6jFRwNGzzJBiznkCzvi5EYpY+YWinieqHb0oY916A==} engines: {node: '>=20.0.0'} + '@azure-rest/core-client@2.8.0': + resolution: {integrity: sha512-F1ybHeN+++QhyFCF/ehLUEvrOB6fehPdFBFtGdj0C3B2lpQ9zkPiO5JDgsqc6IfjuUe6b3dAbXK0a7+VgSGfhw==} + engines: {node: '>=22.0.0'} + '@azure/abort-controller@1.1.0': resolution: {integrity: sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==} engines: {node: '>=12.0.0'} @@ -3192,9 +3203,9 @@ packages: resolution: {integrity: sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==} engines: {node: '>=18.0.0'} - '@azure/core-client@1.10.1': - resolution: {integrity: sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==} - engines: {node: '>=20.0.0'} + '@azure/core-client@1.11.0': + resolution: {integrity: sha512-JjQWO6akOck45PH/XBrxzsQGAiKrfFl4m5iggJ0ItMIz5omRufOXWpqCPpdjKN3vKDzlSUvFjaMb7Zwf0gvAdA==} + engines: {node: '>=22.0.0'} '@azure/core-http-compat@2.3.1': resolution: {integrity: sha512-az9BkXND3/d5VgdRRQVkiJb2gOmDU8Qcq4GvjtBmDICNiQ9udFmDk4ZpSB5Qq1OmtDJGlQAfBaS4palFsazQ5g==} @@ -3212,9 +3223,9 @@ packages: resolution: {integrity: sha512-VxLk4AHLyqcHsfKe4MZ6IQ+D+ShuByy+RfStKfSjxJoL3WBWq17VNmrz8aT8etKzqc2nAeIyLxScjpzsS4fz8w==} engines: {node: '>=18.0.0'} - '@azure/core-rest-pipeline@1.22.2': - resolution: {integrity: sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==} - engines: {node: '>=20.0.0'} + '@azure/core-rest-pipeline@1.25.0': + resolution: {integrity: sha512-bMs8ekJLjX8wPV+9IPBges1SLPyuDtE9g5gLDWOpxzKcoOFQnpLGkbcT1tdw3FaAmDS1gnPmMmJ6y/T5B96kIA==} + engines: {node: '>=22.0.0'} '@azure/core-tracing@1.3.1': resolution: {integrity: sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==} @@ -3262,9 +3273,9 @@ packages: resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==} engines: {node: '>=20.0.0'} - '@azure/monitor-opentelemetry-exporter@1.0.0-beta.31': - resolution: {integrity: sha512-fH/vFMWOHwN/qdJ1SxVtsJ9zWIGWJdy/tZiVVPsFbpbR4NT49J5Im72iCcTyvABRPfIkMz/zsD58Yilf0yiEZw==} - engines: {node: '>=18.0.0'} + '@azure/monitor-opentelemetry-exporter@1.0.0-beta.43': + resolution: {integrity: sha512-551lMY6gSf7TO+j15nmQ23+nG9fExb664TH9RDs9zUul1xHt3NUtfsZe90nNhOzMEeg+I1f7zn955dvH5o6yjA==} + engines: {node: '>=22.0.0'} '@azure/ms-rest-js@1.11.2': resolution: {integrity: sha512-2AyQ1IKmLGKW7DU3/x3TsTBzZLcbC9YRI+yuDPuXAQrv3zar340K9wsxU413kHFIDjkWNCo9T0w5VtwcyWxhbQ==} @@ -4065,217 +4076,217 @@ packages: resolution: {integrity: sha512-isfLLwksH3yHkFXfCI2Gcaqg7wGGHZZwunoJzEZk0yKYIokgre6hYVFibKL3SYAoR1kBXova8LB+JoO5vZzi9w==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-cascade-layers@5.0.2': resolution: {integrity: sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-color-function-display-p3-linear@1.0.1': resolution: {integrity: sha512-E5qusdzhlmO1TztYzDIi8XPdPoYOjoTY6HBYBCYSj+Gn4gQRBlvjgPQXzfzuPQqt8EhkC/SzPKObg4Mbn8/xMg==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-color-function@4.0.12': resolution: {integrity: sha512-yx3cljQKRaSBc2hfh8rMZFZzChaFgwmO2JfFgFr1vMcF3C/uyy5I4RFIBOIWGq1D+XbKCG789CGkG6zzkLpagA==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-color-mix-function@3.0.12': resolution: {integrity: sha512-4STERZfCP5Jcs13P1U5pTvI9SkgLgfMUMhdXW8IlJWkzOOOqhZIjcNhWtNJZes2nkBDsIKJ0CJtFtuaZ00moag==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-color-mix-variadic-function-arguments@1.0.2': resolution: {integrity: sha512-rM67Gp9lRAkTo+X31DUqMEq+iK+EFqsidfecmhrteErxJZb6tUoJBVQca1Vn1GpDql1s1rD1pKcuYzMsg7Z1KQ==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-content-alt-text@2.0.8': resolution: {integrity: sha512-9SfEW9QCxEpTlNMnpSqFaHyzsiRpZ5J5+KqCu1u5/eEJAWsMhzT40qf0FIbeeglEvrGRMdDzAxMIz3wqoGSb+Q==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-contrast-color-function@2.0.12': resolution: {integrity: sha512-YbwWckjK3qwKjeYz/CijgcS7WDUCtKTd8ShLztm3/i5dhh4NaqzsbYnhm4bjrpFpnLZ31jVcbK8YL77z3GBPzA==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-exponential-functions@2.0.9': resolution: {integrity: sha512-abg2W/PI3HXwS/CZshSa79kNWNZHdJPMBXeZNyPQFbbj8sKO3jXxOt/wF7juJVjyDTc6JrvaUZYFcSBZBhaxjw==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-font-format-keywords@4.0.0': resolution: {integrity: sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-gamut-mapping@2.0.11': resolution: {integrity: sha512-fCpCUgZNE2piVJKC76zFsgVW1apF6dpYsqGyH8SIeCcM4pTEsRTWTLCaJIMKFEundsCKwY1rwfhtrio04RJ4Dw==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-gradients-interpolation-method@5.0.12': resolution: {integrity: sha512-jugzjwkUY0wtNrZlFeyXzimUL3hN4xMvoPnIXxoZqxDvjZRiSh+itgHcVUWzJ2VwD/VAMEgCLvtaJHX+4Vj3Ow==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-hwb-function@4.0.12': resolution: {integrity: sha512-mL/+88Z53KrE4JdePYFJAQWFrcADEqsLprExCM04GDNgHIztwFzj0Mbhd/yxMBngq0NIlz58VVxjt5abNs1VhA==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-ic-unit@4.0.4': resolution: {integrity: sha512-yQ4VmossuOAql65sCPppVO1yfb7hDscf4GseF0VCA/DTDaBc0Wtf8MTqVPfjGYlT5+2buokG0Gp7y0atYZpwjg==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-initial@2.0.1': resolution: {integrity: sha512-L1wLVMSAZ4wovznquK0xmC7QSctzO4D0Is590bxpGqhqjboLXYA16dWZpfwImkdOgACdQ9PqXsuRroW6qPlEsg==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-is-pseudo-class@5.0.3': resolution: {integrity: sha512-jS/TY4SpG4gszAtIg7Qnf3AS2pjcUM5SzxpApOrlndMeGhIbaTzWBzzP/IApXoNWEW7OhcjkRT48jnAUIFXhAQ==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-light-dark-function@2.0.11': resolution: {integrity: sha512-fNJcKXJdPM3Lyrbmgw2OBbaioU7yuKZtiXClf4sGdQttitijYlZMD5K7HrC/eF83VRWRrYq6OZ0Lx92leV2LFA==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-logical-float-and-clear@3.0.0': resolution: {integrity: sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-logical-overflow@2.0.0': resolution: {integrity: sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-logical-overscroll-behavior@2.0.0': resolution: {integrity: sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-logical-resize@3.0.0': resolution: {integrity: sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-logical-viewport-units@3.0.4': resolution: {integrity: sha512-q+eHV1haXA4w9xBwZLKjVKAWn3W2CMqmpNpZUk5kRprvSiBEGMgrNH3/sJZ8UA3JgyHaOt3jwT9uFa4wLX4EqQ==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-media-minmax@2.0.9': resolution: {integrity: sha512-af9Qw3uS3JhYLnCbqtZ9crTvvkR+0Se+bBqSr7ykAnl9yKhk6895z9rf+2F4dClIDJWxgn0iZZ1PSdkhrbs2ig==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-media-queries-aspect-ratio-number-values@3.0.5': resolution: {integrity: sha512-zhAe31xaaXOY2Px8IYfoVTB3wglbJUVigGphFLj6exb7cjZRH9A6adyE22XfFK3P2PzwRk0VDeTJmaxpluyrDg==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-nested-calc@4.0.0': resolution: {integrity: sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-normalize-display-values@4.0.0': resolution: {integrity: sha512-HlEoG0IDRoHXzXnkV4in47dzsxdsjdz6+j7MLjaACABX2NfvjFS6XVAnpaDyGesz9gK2SC7MbNwdCHusObKJ9Q==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-oklab-function@4.0.12': resolution: {integrity: sha512-HhlSmnE1NKBhXsTnNGjxvhryKtO7tJd1w42DKOGFD6jSHtYOrsJTQDKPMwvOfrzUAk8t7GcpIfRyM7ssqHpFjg==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-progressive-custom-properties@4.2.1': resolution: {integrity: sha512-uPiiXf7IEKtUQXsxu6uWtOlRMXd2QWWy5fhxHDnPdXKCQckPP3E34ZgDoZ62r2iT+UOgWsSbM4NvHE5m3mAEdw==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-random-function@2.0.1': resolution: {integrity: sha512-q+FQaNiRBhnoSNo+GzqGOIBKoHQ43lYz0ICrV+UudfWnEF6ksS6DsBIJSISKQT2Bvu3g4k6r7t0zYrk5pDlo8w==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-relative-color-syntax@3.0.12': resolution: {integrity: sha512-0RLIeONxu/mtxRtf3o41Lq2ghLimw0w9ByLWnnEVuy89exmEEq8bynveBxNW3nyHqLAFEeNtVEmC1QK9MZ8Huw==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-scope-pseudo-class@4.0.1': resolution: {integrity: sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-sign-functions@1.1.4': resolution: {integrity: sha512-P97h1XqRPcfcJndFdG95Gv/6ZzxUBBISem0IDqPZ7WMvc/wlO+yU0c5D/OCpZ5TJoTt63Ok3knGk64N+o6L2Pg==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-stepped-value-functions@4.0.9': resolution: {integrity: sha512-h9btycWrsex4dNLeQfyU3y3w40LMQooJWFMm/SK9lrKguHDcFl4VMkncKKoXi2z5rM9YGWbUQABI8BT2UydIcA==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-text-decoration-shorthand@4.0.3': resolution: {integrity: sha512-KSkGgZfx0kQjRIYnpsD7X2Om9BUXX/Kii77VBifQW9Ih929hK0KNjVngHDH0bFB9GmfWcR9vJYJJRvw/NQjkrA==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-trigonometric-functions@4.0.9': resolution: {integrity: sha512-Hnh5zJUdpNrJqK9v1/E3BbrQhaDTj5YiX7P61TOvUhoDHnUmsNNxcDAgkQ32RrcWx9GVUvfUNPcUkn8R3vIX6A==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/postcss-unset-value@4.0.0': resolution: {integrity: sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/selector-resolve-nested@3.1.0': resolution: {integrity: sha512-mf1LEW0tJLKfWyvn5KdDrhpxHyuxpbNwTIwOYLIvsTffeyOf85j5oIzfG0yosxDgx/sswlqBnESYUcQH0vgZ0g==} @@ -4293,7 +4304,7 @@ packages: resolution: {integrity: sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@ctrl/tinycolor@3.6.1': resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} @@ -5270,6 +5281,14 @@ packages: resolution: {integrity: sha512-IKJBQxh91qJ+3ssRly5hYEJ8NDHu9oY/B1PXVSCWf7zytmYO9RNLB0Ox9XQ/fJ8m6gY6Q6NtBWlmXfaXt5Uc4Q==} engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.219.0': + resolution: {integrity: sha512-FFx7YnaYJlIjqWW/AG/yAZ0L/NEY724PipXXXQLdtZPbLwBGbUMTGL1i/esI56TWfTUXxhLfpgrnWJCG8aUJyg==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/api-logs@0.220.0': + resolution: {integrity: sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==} + engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.52.1': resolution: {integrity: sha512-qnSqB2DQ9TPP96dl8cDubDvrUyWc0/sK81xHTK8eSUspzDM3bsewX903qclQFvVhgStjRWdC5bLb3kQqMkfV5A==} engines: {node: '>=14'} @@ -5282,15 +5301,15 @@ packages: resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} - '@opentelemetry/context-async-hooks@1.30.1': - resolution: {integrity: sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA==} - engines: {node: '>=14'} + '@opentelemetry/configuration@0.220.0': + resolution: {integrity: sha512-glfIVKnZevRin8fY/9uES/mhRtMT1lGINLHc9MIo5fTQZXswEEHamJtgjv4MTtzgnhHGC92mIS/0lzAUZMyE0w==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/api': ^1.9.0 - '@opentelemetry/core@1.25.1': - resolution: {integrity: sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==} - engines: {node: '>=14'} + '@opentelemetry/context-async-hooks@2.9.0': + resolution: {integrity: sha512-OQ0vzvbZBiUhjqLnUaoNfYmP8553Crr3aggB4y0ZUi815mZ7idpdJXQmoKdeBKJelYttoBlLSSHubmyw3wvX4w==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -5312,69 +5331,75 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/exporter-logs-otlp-grpc@0.57.2': - resolution: {integrity: sha512-eovEy10n3umjKJl2Ey6TLzikPE+W4cUQ4gCwgGP1RqzTGtgDra0WjIqdy29ohiUKfvmbiL3MndZww58xfIvyFw==} - engines: {node: '>=14'} + '@opentelemetry/core@2.9.0': + resolution: {integrity: sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/exporter-logs-otlp-grpc@0.220.0': + resolution: {integrity: sha512-s0sRPCSlXYqlgObOpCftomJllp3LfUL9FobQ5csg2172ydVhSEnu1ptpsVBJadazs5nUNp7vDuLE03FAFWTLOQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-logs-otlp-http@0.57.2': - resolution: {integrity: sha512-0rygmvLcehBRp56NQVLSleJ5ITTduq/QfU7obOkyWgPpFHulwpw2LYTqNIz5TczKZuy5YY+5D3SDnXZL1tXImg==} - engines: {node: '>=14'} + '@opentelemetry/exporter-logs-otlp-http@0.220.0': + resolution: {integrity: sha512-8186thl+pTw64iz/qEEen5oJZoZ/gO73XruChdaGlYdWOdBIQ42r+vHLf6a7vIDqTD4b8ZOoMlyxptanECaI9A==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-logs-otlp-proto@0.57.2': - resolution: {integrity: sha512-ta0ithCin0F8lu9eOf4lEz9YAScecezCHkMMyDkvd9S7AnZNX5ikUmC5EQOQADU+oCcgo/qkQIaKcZvQ0TYKDw==} - engines: {node: '>=14'} + '@opentelemetry/exporter-logs-otlp-proto@0.220.0': + resolution: {integrity: sha512-8LZAxdJ0ENDAFwr4j0oY35mHBltiSzvlhdQAPGiC7p9VnxtuSq4SW1gfBAdW6t6hiQG6OwUl8w7KHaOdJPKHWg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-metrics-otlp-grpc@0.57.2': - resolution: {integrity: sha512-r70B8yKR41F0EC443b5CGB4rUaOMm99I5N75QQt6sHKxYDzSEc6gm48Diz1CI1biwa5tDPznpylTrywO/pT7qw==} - engines: {node: '>=14'} + '@opentelemetry/exporter-metrics-otlp-grpc@0.220.0': + resolution: {integrity: sha512-U128izvJfX/dW9jRGP0gIfadR1Hg7ft3UEGIeRxLFK70m2BWw6AtNCOnsUygpw2zCgR/ygdWbGpcL6TmhW0ZGw==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-metrics-otlp-http@0.57.2': - resolution: {integrity: sha512-ttb9+4iKw04IMubjm3t0EZsYRNWr3kg44uUuzfo9CaccYlOh8cDooe4QObDUkvx9d5qQUrbEckhrWKfJnKhemA==} - engines: {node: '>=14'} + '@opentelemetry/exporter-metrics-otlp-http@0.220.0': + resolution: {integrity: sha512-Yqt3RBw/bRVncaE9qIIhk4WfjbAQqXuP9FgAaU+IKPndnLEp/cUqZlSC324+bpmduRz7DoTjig8Ub0PeILWXUA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-metrics-otlp-proto@0.57.2': - resolution: {integrity: sha512-HX068Q2eNs38uf7RIkNN9Hl4Ynl+3lP0++KELkXMCpsCbFO03+0XNNZ1SkwxPlP9jrhQahsMPMkzNXpq3fKsnw==} - engines: {node: '>=14'} + '@opentelemetry/exporter-metrics-otlp-proto@0.220.0': + resolution: {integrity: sha512-lyO+IQBdSvqHN/ZOW/OzrSWemtfD+HgWngn+HBNLhjy0YrCQQTz0OE/kSekH2Pl340dn9DWzhqHdz5Eftr+HLA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-prometheus@0.217.0': - resolution: {integrity: sha512-U9MCXxJu0sBCh5aEkylYRR4xVIL8D1CW6dGwvYXbfFr0qveSorfD0XJchCAWoW6QfAAIcY/yxjf4Dj8OgkHBPw==} + '@opentelemetry/exporter-prometheus@0.220.0': + resolution: {integrity: sha512-JZD5DL/NBpVd2BHefvYosm3G40UZ/KzExLv5tc0eZe0CtrsHHtcOk3YPUxR2EINmUeBf8+w5UReTV8fFPn95lA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-trace-otlp-grpc@0.57.2': - resolution: {integrity: sha512-gHU1vA3JnHbNxEXg5iysqCWxN9j83d7/epTYBZflqQnTyCC4N7yZXn/dMM+bEmyhQPGjhCkNZLx4vZuChH1PYw==} - engines: {node: '>=14'} + '@opentelemetry/exporter-trace-otlp-grpc@0.220.0': + resolution: {integrity: sha512-bv1xmNhmNwIM6MdUBw4yYuJeVcEViVLk3uD69vOQMwueHBnfyl/u0HnBlB1FNY/Te0UOzJzvcbyR8wN6b+iGbA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-trace-otlp-http@0.57.2': - resolution: {integrity: sha512-sB/gkSYFu+0w2dVQ0PWY9fAMl172PKMZ/JrHkkW8dmjCL0CYkmXeE+ssqIL/yBUTPOvpLIpenX5T9RwXRBW/3g==} - engines: {node: '>=14'} + '@opentelemetry/exporter-trace-otlp-http@0.220.0': + resolution: {integrity: sha512-/+ExB3lRkf+erv4PnoywyL7RHKITidxtUpUTS55k7OQ0dB42S7gEF1gry7swb9MSm1hYLUhJg4QQh9W8SpwwqA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-trace-otlp-proto@0.57.2': - resolution: {integrity: sha512-awDdNRMIwDvUtoRYxRhja5QYH6+McBLtoz1q9BeEsskhZcrGmH/V1fWpGx8n+Rc+542e8pJA6y+aullbIzQmlw==} - engines: {node: '>=14'} + '@opentelemetry/exporter-trace-otlp-proto@0.220.0': + resolution: {integrity: sha512-voTAD8XgJxlK7zLkXh8EzMB09zrQr3tyY/BsnDTlDiQU/UdK58MZ63A3mUjdEDrxMjCVmBHU3WQJhRmQe+Dvzg==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-zipkin@1.30.1': - resolution: {integrity: sha512-6S2QIMJahIquvFaaxmcwpvQQRD/YFaMTNoIxrfPIPOeITN+a8lfEcPDxNxn8JDAaxkg+4EnXhz8upVDYenoQjA==} - engines: {node: '>=14'} + '@opentelemetry/exporter-zipkin@2.9.0': + resolution: {integrity: sha512-RwINoce2BH8T4obT5pMcAla2sWma1YZvYuaktWmTluQ0PkQdvv5D060rWI1+kawX+J2qBRcMbwrZJJNcMJUauQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.0.0 @@ -5390,9 +5415,9 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-http@0.52.1': - resolution: {integrity: sha512-dG/aevWhaP+7OLv4BQQSEKMJv8GyeOp3Wxl31NHqE8xo9/fYMfEljiZphUHIfyg4gnZ9swMyWjfOQs5GUQe54Q==} - engines: {node: '>=14'} + '@opentelemetry/instrumentation-http@0.220.0': + resolution: {integrity: sha512-Szt4dO2Boz2CDr38DaSw/lnqwhwKl+IAdgNGEGgSm2Anb+fwPtIAGmIwkhsLLN69QQZQE96JxjMKYY4rlRkYKw==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 @@ -5408,45 +5433,45 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation@0.52.1': - resolution: {integrity: sha512-uXJbYU/5/MBHjMp1FqrILLRuiJCs3Ofk0MeRDk8g1S1gD47U8X3JnSwcMO1rtRo1x1a7zKaQHaoYu49p/4eSKw==} - engines: {node: '>=14'} + '@opentelemetry/instrumentation@0.220.0': + resolution: {integrity: sha512-xQx3E2WxP1mDvKzxLxX+CTCtNLa560YJZ3087qYHerl2YmiKpv7AH+dAy7vmx+eVrZ5BwhfWUAVoKOoxCNHcpw==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation@0.57.2': - resolution: {integrity: sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg==} + '@opentelemetry/instrumentation@0.52.1': + resolution: {integrity: sha512-uXJbYU/5/MBHjMp1FqrILLRuiJCs3Ofk0MeRDk8g1S1gD47U8X3JnSwcMO1rtRo1x1a7zKaQHaoYu49p/4eSKw==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/otlp-exporter-base@0.57.2': - resolution: {integrity: sha512-XdxEzL23Urhidyebg5E6jZoaiW5ygP/mRjxLHixogbqwDy2Faduzb5N0o/Oi+XTIJu+iyxXdVORjXax+Qgfxag==} - engines: {node: '>=14'} + '@opentelemetry/otlp-exporter-base@0.220.0': + resolution: {integrity: sha512-CXYo8UD5Mn9YbgebO2EL4wejtA+gxLmLiu6HCk2KH2BR7XhFN6/6p1UlCb23DYCjeYkndevLHuejCCN1yx4+OQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/otlp-grpc-exporter-base@0.57.2': - resolution: {integrity: sha512-USn173KTWy0saqqRB5yU9xUZ2xdgb1Rdu5IosJnm9aV4hMTuFFRTUsQxbgc24QxpCHeoKzzCSnS/JzdV0oM2iQ==} - engines: {node: '>=14'} + '@opentelemetry/otlp-grpc-exporter-base@0.220.0': + resolution: {integrity: sha512-/eIkBPMBTIvM3x/0mDX4aJeSkYifYClnBPr68PL1h5LV4VQv4+SV6CGrpiZ4fIWDnobVmhTWCm1J/QRdAWUfvA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/otlp-transformer@0.57.2': - resolution: {integrity: sha512-48IIRj49gbQVK52jYsw70+Jv+JbahT8BqT2Th7C4H7RCM9d0gZ5sgNPoMpWldmfjvIsSgiGJtjfk9MeZvjhoig==} - engines: {node: '>=14'} + '@opentelemetry/otlp-transformer@0.220.0': + resolution: {integrity: sha512-lXGrv7KXZ0gNH9SVNUaa6vv6phVYGvJxfXAlMbzbakiXru75f5MZl8Z7oqiMMQD77riVHJCFlQvbZs/VVN2/4A==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/propagator-b3@1.30.1': - resolution: {integrity: sha512-oATwWWDIJzybAZ4pO76ATN5N6FFbOA1otibAVlS8v90B4S1wClnhRUk7K+2CHAwN1JKYuj4jh/lpCEG5BAqFuQ==} - engines: {node: '>=14'} + '@opentelemetry/propagator-b3@2.9.0': + resolution: {integrity: sha512-WrOT1WsOUG+B7hstD2RYoMPIOK76G8E9AQHhMjUvrQaGx/oA7rPWQvvr1Rqv7+yy4R0ZMVwWLC4vW2xnkgWPAQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/propagator-jaeger@1.30.1': - resolution: {integrity: sha512-Pj/BfnYEKIOImirH76M4hDaBSx6HyZ2CXUqk+Kj02m6BB80c/yo4BdWkn/1gDFfU+YPY+bPR2U0DKBfdxCKwmg==} - engines: {node: '>=14'} + '@opentelemetry/propagator-jaeger@2.9.0': + resolution: {integrity: sha512-4mYGty27rYvSM0jtp1ZUOqd3LfVRCYg9H5G9OFzSx5HViYToU21MFhWfco7x1HwXr7ER8yGOiCIHZUwjPksc0Q==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -5462,33 +5487,45 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/resources@2.7.1': - resolution: {integrity: sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==} + '@opentelemetry/resources@2.8.0': + resolution: {integrity: sha512-qmXQ27ilDbUK/vGMqwL8D4/rhn76C+sherM4wTbjlfknR8Nvfc/hCxjRJPhkzZzUsPiNg16SA31NxMabwttRjg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/sdk-logs@0.57.2': - resolution: {integrity: sha512-TXFHJ5c+BKggWbdEQ/inpgIzEmS2BGQowLE9UhsMd7YYlUfBQJ4uax0VF/B5NYigdM/75OoJGhAV3upEhK+3gg==} - engines: {node: '>=14'} + '@opentelemetry/resources@2.9.0': + resolution: {integrity: sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-logs@0.219.0': + resolution: {integrity: sha512-s6lTKRakaPClvKoWHRChxnXjDMkM/TQ30ff78jN6EBGf7MI7VzANE5PU3f4z9qDUudWjvZjOLHG0rBnBKYvoXA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.4.0 <1.10.0' - '@opentelemetry/sdk-metrics@1.30.1': - resolution: {integrity: sha512-q9zcZ0Okl8jRgmy7eNW3Ku1XSgg3sDLa5evHZpCwjspw7E8Is4K/haRPDJrBcX3YSn/Y7gUvFnByNYEKQNbNog==} - engines: {node: '>=14'} + '@opentelemetry/sdk-logs@0.220.0': + resolution: {integrity: sha512-WywcTkQtv2iNmt+6y5Kcd4rzvx9bLVsBa2Nwcmg01IUaBTkTow3W4d9KE5vNBpEDtb9tp21WcRBY/lANRrApYA==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/api': '>=1.4.0 <1.10.0' - '@opentelemetry/sdk-metrics@2.7.1': - resolution: {integrity: sha512-MpDJdkiFDs3Pm1RHO3KByuZbuBdJEXEAkiC0+yJdsZGVCdf1RpHR6n+LHDcS7ffmfrt5kVCzJSCfm4z2C7v0uQ==} + '@opentelemetry/sdk-metrics@2.8.0': + resolution: {integrity: sha512-UDBGaj6W0Rgy5rTTaoxs8gVGF/aGkAKyjurJv7se6wjRxJu7FoquTLT/vt54DZfo4crbprYfhX/SOK9+BPw1qg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.9.0 <1.10.0' - '@opentelemetry/sdk-node@0.57.2': - resolution: {integrity: sha512-8BaeqZyN5sTuPBtAoY+UtKwXBdqyuRKmekN5bFzAO40CgbGzAxfTpiL3PBerT7rhZ7p2nBdq7FaMv/tBQgHE4A==} - engines: {node: '>=14'} + '@opentelemetry/sdk-metrics@2.9.0': + resolution: {integrity: sha512-Xx8RGS4H5XEBl01WuCreMIpiah9cCXMbSkeuIePPdD2cUpq/vUzYmj8E/MK1OsbOc93FuAD4jfn2WOacKwLn7Q==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.9.0 <1.10.0' + + '@opentelemetry/sdk-node@0.220.0': + resolution: {integrity: sha512-wHtGyHhSKHNH3fym33xRu4Ef/HXTFvX8eQ42xdQdEO9LYx9Y2qNyBDJytyqVlvmo6abWZlNYTUthuAGUMYqYnQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' @@ -5504,9 +5541,21 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/sdk-trace-node@1.30.1': - resolution: {integrity: sha512-cBjYOINt1JxXdpw1e5MlHmFRc5fgj4GW/86vsKFxJCJ8AL4PdVtYH41gWwl4qd4uQjqEL1oJVrXkSy5cnduAnQ==} - engines: {node: '>=14'} + '@opentelemetry/sdk-trace-base@2.8.0': + resolution: {integrity: sha512-mhU4jp+vW0mGbFRd+GeXHvmfA4aDqWjBjLC3pE5XMpLs0IE2ryYb019Ts2AQrOq67gaTF25D91+fgvEHDZEnuQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-base@2.9.0': + resolution: {integrity: sha512-cp9zmTl62R8PJrpvFcmc8N2JQU/xfa0S+61q511Nji+QxCfZ8Ifvg7H27G8cANe4crg4RTrWsVvanHiXjSp6ag==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-node@2.9.0': + resolution: {integrity: sha512-ec9a7ps37huy5itYk0MalaZdSLlM6AXWp/FhtEjgMpp5leEGojBDvAl/UWttQnkMZOvFHKzRESn8TD3yKTF5nQ==} + engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -5516,9 +5565,11 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/semantic-conventions@1.25.1': - resolution: {integrity: sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==} - engines: {node: '>=14'} + '@opentelemetry/sdk-trace@2.9.0': + resolution: {integrity: sha512-sGA19HvtrrSKYsseHphluH6j3p6Xa3fqc7c7y8f/7mYWejc1lyDFcpSdD1kYa50HCLUeEo4zA5bW0pniaPszuw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' '@opentelemetry/semantic-conventions@1.28.0': resolution: {integrity: sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==} @@ -5528,6 +5579,10 @@ packages: resolution: {integrity: sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg==} engines: {node: '>=14'} + '@opentelemetry/semantic-conventions@1.43.0': + resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} + engines: {node: '>=14'} + '@oxc-parser/binding-android-arm-eabi@0.121.0': resolution: {integrity: sha512-n07FQcySwOlzap424/PLMtOkbS7xOu8nsJduKL8P3COGHKgKoDYXwoAHCbChfgFpHnviehrLWIPX0lKGtbEk/A==} engines: {node: ^20.19.0 || >=22.12.0} @@ -6161,15 +6216,9 @@ packages: '@protobufjs/codegen@2.0.5': resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} - '@protobufjs/eventemitter@1.1.0': - resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} - '@protobufjs/eventemitter@1.1.1': resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} - '@protobufjs/fetch@1.1.0': - resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} - '@protobufjs/fetch@1.1.1': resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} @@ -6807,8 +6856,8 @@ packages: '@storybook/addon-vitest@10.4.2': resolution: {integrity: sha512-gq1ZVr0IOLgiS2PzaJqHxKLczwrXvA5g3W2k/FVJA19fJNFNUut1IyQCQRSJTXLLXbnNaa8I0wjGGc2BoLarJg==} peerDependencies: - '@vitest/browser': 4.1.8 - '@vitest/browser-playwright': 4.1.8 + '@vitest/browser': 4.1.10 + '@vitest/browser-playwright': 4.1.10 '@vitest/runner': ^3.0.0 || ^4.0.0 storybook: ^10.4.2 vitest: ^3.0.0 || ^4.0.0 @@ -7319,9 +7368,9 @@ packages: engines: {node: '>=16.20.0'} hasBin: true - '@typespec/ts-http-runtime@0.3.2': - resolution: {integrity: sha512-IlqQ/Gv22xUC1r/WQm4StLkYQmaaTsXAhUVsNE0+xiyf0yRFiH5++q78U3bw6bLKDCTmh0uqKB9eG9+Bt75Dkg==} - engines: {node: '>=20.0.0'} + '@typespec/ts-http-runtime@0.3.7': + resolution: {integrity: sha512-JVUD8X2tfDMWjcjLs4yVxxVrS8yR5vnh386GAXT9Qj79nBxxXSaHFQZg5FweLmT8HlPQ3kii6noUB+Z9RN7DvQ==} + engines: {node: '>=22.0.0'} '@umijs/route-utils@4.0.3': resolution: {integrity: sha512-zPEcYhl1cSfkSRDzzGgoD1mDvGjxoOTJFvkn55srfgdQ3NZe2ZMCScCU6DEnOxuKP1XDVf8pqyqCDVd2+RCQIw==} @@ -7352,30 +7401,30 @@ packages: babel-plugin-react-compiler: optional: true - '@vitest/browser-playwright@4.1.8': - resolution: {integrity: sha512-SR7FqgegaexEg73xvf3ArtygXegagMdXnL0EZMpxrWvvhQxvicD/E8p0ib0J91riPRtQUViyh67Xjw3NqvyhVg==} + '@vitest/browser-playwright@4.1.10': + resolution: {integrity: sha512-nMoXGEiRpT7m3W7NsbvrM2aKNwiNHZf+zEpUCvMteGjZFvfT96Q9fh7QyB98dvDWXiKvrLxA7bJ1mCOOv+JQPw==} peerDependencies: playwright: 1.59.0 - vitest: 4.1.8 + vitest: 4.1.10 - '@vitest/browser@4.1.8': - resolution: {integrity: sha512-u21VzX07HzlJYpFgkxmjEXar/tG2UqWGgyGG/46SrrPc7rSdCTPw5vuowopO9CIqF8UCUQzDFdbVnNpw6N0BfQ==} + '@vitest/browser@4.1.10': + resolution: {integrity: sha512-UDwuWGwXj646CBx/bQHOaJSX7np0I8JL/UKQYa1e4QrVHH8VdWtx8eaOuf8sy0ShwDgR6NjJAsp5eF6vjF6qng==} peerDependencies: - vitest: 4.1.8 + vitest: 4.1.10 - '@vitest/coverage-istanbul@4.1.8': - resolution: {integrity: sha512-/h514nMZMKI6foh21mVgO1zlCH6pdDamwKMbla1uLU2GMxTlfp0PQMxovWozmzQdCIQYZ2XXEzg2zNZom2zAOg==} + '@vitest/coverage-istanbul@4.1.10': + resolution: {integrity: sha512-AyNJ5pQRFqCX7pwB9PSTmoVKPaZ4H5IEVJfJsT+q1DYkXvZMEFYgJlyk5sfStmt9rVYRyYYRRsuBeImCOc39ww==} peerDependencies: - vitest: 4.1.8 + vitest: 4.1.10 '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - '@vitest/expect@4.1.8': - resolution: {integrity: sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==} + '@vitest/expect@4.1.10': + resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} - '@vitest/mocker@4.1.8': - resolution: {integrity: sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==} + '@vitest/mocker@4.1.10': + resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} peerDependencies: msw: ^2.4.9 vite: 8.0.16 @@ -7388,26 +7437,26 @@ packages: '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/pretty-format@4.1.8': - resolution: {integrity: sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==} + '@vitest/pretty-format@4.1.10': + resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} - '@vitest/runner@4.1.8': - resolution: {integrity: sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==} + '@vitest/runner@4.1.10': + resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} - '@vitest/snapshot@4.1.8': - resolution: {integrity: sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==} + '@vitest/snapshot@4.1.10': + resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - '@vitest/spy@4.1.8': - resolution: {integrity: sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==} + '@vitest/spy@4.1.10': + resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - '@vitest/utils@4.1.8': - resolution: {integrity: sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==} + '@vitest/utils@4.1.10': + resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -7541,6 +7590,10 @@ packages: resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} engines: {node: '>=12.0'} + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} @@ -7769,7 +7822,7 @@ packages: engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} @@ -7783,8 +7836,8 @@ packages: resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} engines: {node: '>=4'} - axios@1.16.0: - resolution: {integrity: sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==} + axios@1.18.0: + resolution: {integrity: sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==} azurite@3.35.0: resolution: {integrity: sha512-GzKmi+/5U0baNRjEEVtBMLpLuIKEJ0uSh0VWBzOI4qe4f5ziJyoZQmcTO7QhxZTF6+rphj7TZS3PtJY7uiiacA==} @@ -8162,6 +8215,9 @@ packages: cjs-module-lexer@1.4.3: resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + cjs-module-lexer@2.2.0: + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} + class-transformer@0.5.1: resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} @@ -8467,19 +8523,19 @@ packages: resolution: {integrity: sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 css-declaration-sorter@7.3.0: resolution: {integrity: sha512-LQF6N/3vkAMYF4xoHLJfG718HRJh34Z8BnNhd6bosOMIVjMlhuZK5++oZa3uYAgrI5+7x2o27gUqTR2U/KjUOQ==} engines: {node: ^14 || ^16 || >=18} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 css-has-pseudo@7.0.3: resolution: {integrity: sha512-oG+vKuGyqe/xvEMoxAQrhi7uY16deJR3i7wwhBerVrGQKSqUC5GiOVxTpM9F9B9hw0J+eKeOWLH7E9gZ1Dr5rA==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 css-loader@6.11.0: resolution: {integrity: sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==} @@ -8522,7 +8578,7 @@ packages: resolution: {integrity: sha512-VCtXZAWivRglTZditUfB4StnsWr6YVZ2PRtuxQLKTNRdtAf8tpzaVPE9zXIF3VaSc7O70iK/j1+NXxyQCqdPjQ==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 css-select@4.3.0: resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} @@ -8557,25 +8613,25 @@ packages: resolution: {integrity: sha512-Nhao7eD8ph2DoHolEzQs5CfRpiEP0xa1HBdnFZ82kvqdmbwVBUr2r1QuQ4t1pi+D1ZpqpcO4T+wy/7RxzJ/WPQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 cssnano-preset-default@6.1.2: resolution: {integrity: sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 cssnano-utils@4.0.2: resolution: {integrity: sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 cssnano@6.1.2: resolution: {integrity: sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 csso@5.0.5: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} @@ -8941,8 +8997,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@2.0.0: - resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + es-module-lexer@2.3.1: + resolution: {integrity: sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==} es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} @@ -9124,8 +9180,8 @@ packages: fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - fast-uri@4.0.1: - resolution: {integrity: sha512-j0VntHrljgRKiWdbjL1xECG44OQu5sb7en4b8z2CcRvtDUEG5DAvkXlllrRhvbABR+m2mUiSgYBPvDj/PzB0dg==} + fast-uri@4.1.1: + resolution: {integrity: sha512-YPOs1zD5TG2+EZt+r88LwF6mclA7TPkpwMP7ZN3TO2HiHS8TXvq7QA/17iJsV9dubcLo/f8eEYqMBruyQV21hQ==} fast-xml-builder@1.2.0: resolution: {integrity: sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==} @@ -9282,6 +9338,9 @@ packages: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} + forwarded-parse@2.1.2: + resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==} + forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -9492,7 +9551,7 @@ packages: crossws: ~0.3 graphql: ^15.10.1 || ^16 uWebSockets.js: ^20 - ws: 8.21.0 + ws: 8.21.1 peerDependenciesMeta: '@fastify/websocket': optional: true @@ -9573,10 +9632,6 @@ packages: hash.js@1.1.7: resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - hasown@2.0.4: resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} @@ -9714,6 +9769,10 @@ packages: https-browserify@1.0.0: resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} @@ -9751,7 +9810,7 @@ packages: resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -9792,6 +9851,10 @@ packages: import-in-the-middle@1.15.0: resolution: {integrity: sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==} + import-in-the-middle@3.3.1: + resolution: {integrity: sha512-0rymlHSFLwZ0ixx8DaQkoIyZojJPY2a0K2nEYslhKJ6jIYO/m0IcCb7iQsFPmS7WmKwISZiIrv5Icstrw/CmqA==} + engines: {node: '>=18'} + import-lazy@4.0.0: resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} engines: {node: '>=8'} @@ -10149,7 +10212,7 @@ packages: isomorphic-ws@5.0.0: resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==} peerDependencies: - ws: 8.21.0 + ws: 8.21.1 istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} @@ -10551,10 +10614,6 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.3.5: - resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==} - engines: {node: 20 || >=22} - lru-cache@11.3.6: resolution: {integrity: sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==} engines: {node: 20 || >=22} @@ -10913,10 +10972,6 @@ packages: minimalistic-crypto-utils@1.0.1: resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - minimatch@10.2.4: - resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} - engines: {node: 18 || 20 || >=22} - minimatch@10.2.5: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} @@ -11566,163 +11621,163 @@ packages: resolution: {integrity: sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-calc@9.0.1: resolution: {integrity: sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-clamp@4.1.0: resolution: {integrity: sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==} engines: {node: '>=7.6.0'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-color-functional-notation@7.0.12: resolution: {integrity: sha512-TLCW9fN5kvO/u38/uesdpbx3e8AkTYhMvDZYa9JpmImWuTE99bDQ7GU7hdOADIZsiI9/zuxfAJxny/khknp1Zw==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-color-hex-alpha@10.0.0: resolution: {integrity: sha512-1kervM2cnlgPs2a8Vt/Qbe5cQ++N7rkYo/2rz2BkqJZIHQwaVuJgQH38REHrAi4uM0b1fqxMkWYmese94iMp3w==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-color-rebeccapurple@10.0.0: resolution: {integrity: sha512-JFta737jSP+hdAIEhk1Vs0q0YF5P8fFcj+09pweS8ktuGuZ8pPlykHsk6mPxZ8awDl4TrcxUqJo9l1IhVr/OjQ==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-colormin@6.1.0: resolution: {integrity: sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-convert-values@6.1.0: resolution: {integrity: sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-custom-media@11.0.6: resolution: {integrity: sha512-C4lD4b7mUIw+RZhtY7qUbf4eADmb7Ey8BFA2px9jUbwg7pjTZDl4KY4bvlUV+/vXQvzQRfiGEVJyAbtOsCMInw==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-custom-properties@14.0.6: resolution: {integrity: sha512-fTYSp3xuk4BUeVhxCSJdIPhDLpJfNakZKoiTDx7yRGCdlZrSJR7mWKVOBS4sBF+5poPQFMj2YdXx1VHItBGihQ==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-custom-selectors@8.0.5: resolution: {integrity: sha512-9PGmckHQswiB2usSO6XMSswO2yFWVoCAuih1yl9FVcwkscLjRKjwsjM3t+NIWpSU2Jx3eOiK2+t4vVTQaoCHHg==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-dir-pseudo-class@9.0.1: resolution: {integrity: sha512-tRBEK0MHYvcMUrAuYMEOa0zg9APqirBcgzi6P21OhxtJyJADo/SWBwY1CAwEohQ/6HDaa9jCjLRG7K3PVQYHEA==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-discard-comments@6.0.2: resolution: {integrity: sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-discard-duplicates@6.0.3: resolution: {integrity: sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-discard-empty@6.0.3: resolution: {integrity: sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-discard-overridden@6.0.2: resolution: {integrity: sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-discard-unused@6.0.5: resolution: {integrity: sha512-wHalBlRHkaNnNwfC8z+ppX57VhvS+HWgjW508esjdaEYr3Mx7Gnn2xA4R/CKf5+Z9S5qsqC+Uzh4ueENWwCVUA==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-double-position-gradients@6.0.4: resolution: {integrity: sha512-m6IKmxo7FxSP5nF2l63QbCC3r+bWpFUWmZXZf096WxG0m7Vl1Q1+ruFOhpdDRmKrRS+S3Jtk+TVk/7z0+BVK6g==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-focus-visible@10.0.1: resolution: {integrity: sha512-U58wyjS/I1GZgjRok33aE8juW9qQgQUNwTSdxQGuShHzwuYdcklnvK/+qOWX1Q9kr7ysbraQ6ht6r+udansalA==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-focus-within@9.0.1: resolution: {integrity: sha512-fzNUyS1yOYa7mOjpci/bR+u+ESvdar6hk8XNK/TRR0fiGTp2QT5N+ducP0n3rfH/m9I7H/EQU6lsa2BrgxkEjw==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-font-variant@5.0.0: resolution: {integrity: sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-gap-properties@6.0.0: resolution: {integrity: sha512-Om0WPjEwiM9Ru+VhfEDPZJAKWUd0mV1HmNXqp2C29z80aQ2uP9UVhLc7e3aYMIor/S5cVhoPgYQ7RtfeZpYTRw==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-image-set-function@7.0.0: resolution: {integrity: sha512-QL7W7QNlZuzOwBTeXEmbVckNt1FSmhQtbMRvGGqqU4Nf4xk6KUEQhAoWuMzwbSv5jxiRiSZ5Tv7eiDB9U87znA==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-import@15.1.0: resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-js@4.1.0: resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} engines: {node: ^12 || ^14 || >= 16} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-lab-function@7.0.12: resolution: {integrity: sha512-tUcyRk1ZTPec3OuKFsqtRzW2Go5lehW29XA21lZ65XmzQkz43VY2tyWEC202F7W3mILOjw0voOiuxRGTsN+J9w==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-load-config@6.0.1: resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} engines: {node: '>= 18'} peerDependencies: jiti: 2.6.1 - postcss: 8.5.10 + postcss: 8.5.12 tsx: ^4.8.1 yaml: 2.8.3 peerDependenciesMeta: @@ -11739,216 +11794,216 @@ packages: resolution: {integrity: sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A==} engines: {node: '>= 14.15.0'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 webpack: ^5.105.4 postcss-logical@8.1.0: resolution: {integrity: sha512-pL1hXFQ2fEXNKiNiAgtfA005T9FBxky5zkX6s4GZM2D8RkVgRqz3f4g1JUoq925zXv495qk8UNldDwh8uGEDoA==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-merge-idents@6.0.3: resolution: {integrity: sha512-1oIoAsODUs6IHQZkLQGO15uGEbK3EAl5wi9SS8hs45VgsxQfMnxvt+L+zIr7ifZFIH14cfAeVe2uCTa+SPRa3g==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-merge-longhand@6.0.5: resolution: {integrity: sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-merge-rules@6.1.1: resolution: {integrity: sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-minify-font-values@6.1.0: resolution: {integrity: sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-minify-gradients@6.0.3: resolution: {integrity: sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-minify-params@6.1.0: resolution: {integrity: sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-minify-selectors@6.0.4: resolution: {integrity: sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-modules-extract-imports@3.1.0: resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-modules-local-by-default@4.2.0: resolution: {integrity: sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-modules-scope@3.2.1: resolution: {integrity: sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-modules-values@4.0.0: resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-nested@6.2.0: resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} engines: {node: '>=12.0'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-nesting@13.0.2: resolution: {integrity: sha512-1YCI290TX+VP0U/K/aFxzHzQWHWURL+CtHMSbex1lCdpXD1SoR2sYuxDu5aNI9lPoXpKTCggFZiDJbwylU0LEQ==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-normalize-charset@6.0.2: resolution: {integrity: sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-normalize-display-values@6.0.2: resolution: {integrity: sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-normalize-positions@6.0.2: resolution: {integrity: sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-normalize-repeat-style@6.0.2: resolution: {integrity: sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-normalize-string@6.0.2: resolution: {integrity: sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-normalize-timing-functions@6.0.2: resolution: {integrity: sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-normalize-unicode@6.1.0: resolution: {integrity: sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-normalize-url@6.0.2: resolution: {integrity: sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-normalize-whitespace@6.0.2: resolution: {integrity: sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-opacity-percentage@3.0.0: resolution: {integrity: sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-ordered-values@6.0.2: resolution: {integrity: sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-overflow-shorthand@6.0.0: resolution: {integrity: sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-page-break@3.0.4: resolution: {integrity: sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-place@10.0.0: resolution: {integrity: sha512-5EBrMzat2pPAxQNWYavwAfoKfYcTADJ8AXGVPcUZ2UkNloUTWzJQExgrzrDkh3EKzmAx1evfTAzF9I8NGcc+qw==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-preset-env@10.4.0: resolution: {integrity: sha512-2kqpOthQ6JhxqQq1FSAAZGe9COQv75Aw8WbsOvQVNJ2nSevc9Yx/IKZGuZ7XJ+iOTtVon7LfO7ELRzg8AZ+sdw==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-pseudo-class-any-link@10.0.1: resolution: {integrity: sha512-3el9rXlBOqTFaMFkWDOkHUTQekFIYnaQY55Rsp8As8QQkpiSgIYEcF/6Ond93oHiDsGb4kad8zjt+NPlOC1H0Q==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-reduce-idents@6.0.3: resolution: {integrity: sha512-G3yCqZDpsNPoQgbDUy3T0E6hqOQ5xigUtBQyrmq3tn2GxlyiL0yyl7H+T8ulQR6kOcHJ9t7/9H4/R2tv8tJbMA==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-reduce-initial@6.1.0: resolution: {integrity: sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-reduce-transforms@6.0.2: resolution: {integrity: sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-replace-overflow-wrap@4.0.0: resolution: {integrity: sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-not@8.0.1: resolution: {integrity: sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA==} engines: {node: '>=18'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser@6.1.2: resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} @@ -11962,19 +12017,19 @@ packages: resolution: {integrity: sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA==} engines: {node: '>=14.0.0'} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-svgo@6.0.3: resolution: {integrity: sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==} engines: {node: ^14 || ^16 || >= 18} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-unique-selectors@6.0.4: resolution: {integrity: sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} @@ -11983,10 +12038,10 @@ packages: resolution: {integrity: sha512-5BxW9l1evPB/4ZIc+2GobEBoKC+h8gPGCMi+jxsYvd2x0mjq7wazk6DrP71pStqxE9Foxh5TVnonbWpFZzXaYg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 - postcss@8.5.10: - resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} + postcss@8.5.12: + resolution: {integrity: sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==} engines: {node: ^10 || ^12 || >=14} pretty-error@4.0.0: @@ -12401,6 +12456,10 @@ packages: resolution: {integrity: sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==} engines: {node: '>=8.6.0'} + require-in-the-middle@8.0.1: + resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==} + engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'} + require-like@0.1.2: resolution: {integrity: sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==} @@ -12612,11 +12671,6 @@ packages: engines: {node: '>=10'} hasBin: true - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} - engines: {node: '>=10'} - hasBin: true - semver@7.7.4: resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} @@ -13079,7 +13133,7 @@ packages: resolution: {integrity: sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: - postcss: 8.5.10 + postcss: 8.5.12 stylis@4.3.6: resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} @@ -13108,8 +13162,8 @@ packages: svg-parser@2.0.4: resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} - svgo@3.3.3: - resolution: {integrity: sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==} + svgo@3.3.4: + resolution: {integrity: sha512-GsNRis4e8jxn2Y9ENz/8lbJ93CstG8svtMnuRaHbiF2LTJ5tK0/q3t/URPq9Zc7zVWBJnNnJMIp6bevK7bSmNg==} engines: {node: '>=14.0.0'} hasBin: true @@ -13245,10 +13299,6 @@ packages: resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} engines: {node: '>=18'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} @@ -13734,20 +13784,20 @@ packages: yaml: optional: true - vitest@4.1.8: - resolution: {integrity: sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==} + vitest@4.1.10: + resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.8 - '@vitest/browser-preview': 4.1.8 - '@vitest/browser-webdriverio': 4.1.8 - '@vitest/coverage-istanbul': 4.1.8 - '@vitest/coverage-v8': 4.1.8 - '@vitest/ui': 4.1.8 + '@vitest/browser-playwright': 4.1.10 + '@vitest/browser-preview': 4.1.10 + '@vitest/browser-webdriverio': 4.1.10 + '@vitest/coverage-istanbul': 4.1.10 + '@vitest/coverage-v8': 4.1.10 + '@vitest/ui': 4.1.10 happy-dom: 20.10.1 jsdom: '*' vite: 8.0.16 @@ -13877,8 +13927,8 @@ packages: webpack: optional: true - websocket-driver@0.7.4: - resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} + websocket-driver@0.7.5: + resolution: {integrity: sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==} engines: {node: '>=0.8.0'} websocket-extensions@0.1.4: @@ -13979,8 +14029,8 @@ packages: write-file-atomic@3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} - ws@8.21.0: - resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} + ws@8.21.1: + resolution: {integrity: sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -14238,13 +14288,13 @@ snapshots: '@alloc/quick-lru@5.2.0': {} - '@amiceli/vitest-cucumber@6.3.0(vitest@4.1.8)': + '@amiceli/vitest-cucumber@6.3.0(vitest@4.1.10)': dependencies: callsites: 4.2.0 minimist: 1.2.8 parsecurrency: 1.1.1 ts-morph: 27.0.2 - vitest: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + vitest: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) '@ant-design/cli@6.3.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: @@ -14382,7 +14432,7 @@ snapshots: dependencies: graphql: 16.12.0 - '@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@graphql-typed-document-node/core': 3.2.0(graphql@16.12.0) '@wry/caches': 1.0.1 @@ -14399,7 +14449,7 @@ snapshots: tslib: 2.8.1 zen-observable-ts: 1.2.5 optionalDependencies: - graphql-ws: 6.0.6(graphql@16.12.0)(ws@8.21.0) + graphql-ws: 6.0.6(graphql@16.12.0)(ws@8.21.1) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) transitivePeerDependencies: @@ -14410,8 +14460,8 @@ snapshots: '@protobufjs/aspromise': 1.1.2 '@protobufjs/base64': 1.1.2 '@protobufjs/codegen': 2.0.5 - '@protobufjs/eventemitter': 1.1.0 - '@protobufjs/fetch': 1.1.0 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 '@protobufjs/float': 1.0.2 '@protobufjs/inquire': 1.1.1 '@protobufjs/path': 1.1.2 @@ -14448,7 +14498,7 @@ snapshots: finalhandler: 2.1.1(supports-color@8.1.1) graphql: 16.12.0 loglevel: 1.9.2 - lru-cache: 11.3.5 + lru-cache: 11.3.6 negotiator: 1.0.0 uuid: 11.1.1 whatwg-mimetype: 4.0.0 @@ -14475,7 +14525,7 @@ snapshots: '@apollo/utils.keyvaluecache@4.0.0': dependencies: '@apollo/utils.logger': 3.0.0 - lru-cache: 11.3.5 + lru-cache: 11.3.6 '@apollo/utils.logger@3.0.0': {} @@ -14536,9 +14586,20 @@ snapshots: dependencies: '@azure/abort-controller': 2.1.2 '@azure/core-auth': 1.10.1 - '@azure/core-rest-pipeline': 1.22.2 + '@azure/core-rest-pipeline': 1.25.0 '@azure/core-tracing': 1.3.1 - '@typespec/ts-http-runtime': 0.3.2 + '@typespec/ts-http-runtime': 0.3.7 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure-rest/core-client@2.8.0': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-rest-pipeline': 1.25.0 + '@azure/core-tracing': 1.3.1 + '@typespec/ts-http-runtime': 0.3.7 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -14567,11 +14628,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@azure/core-client@1.10.1': + '@azure/core-client@1.11.0': dependencies: '@azure/abort-controller': 2.1.2 '@azure/core-auth': 1.10.1 - '@azure/core-rest-pipeline': 1.22.2 + '@azure/core-rest-pipeline': 1.25.0 '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 '@azure/logger': 1.3.0 @@ -14582,8 +14643,8 @@ snapshots: '@azure/core-http-compat@2.3.1': dependencies: '@azure/abort-controller': 2.1.2 - '@azure/core-client': 1.10.1 - '@azure/core-rest-pipeline': 1.22.2 + '@azure/core-client': 1.11.0 + '@azure/core-rest-pipeline': 1.25.0 transitivePeerDependencies: - supports-color @@ -14613,14 +14674,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@azure/core-rest-pipeline@1.22.2': + '@azure/core-rest-pipeline@1.25.0': dependencies: '@azure/abort-controller': 2.1.2 '@azure/core-auth': 1.10.1 '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 '@azure/logger': 1.3.0 - '@typespec/ts-http-runtime': 0.3.2 + '@typespec/ts-http-runtime': 0.3.7 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -14632,7 +14693,7 @@ snapshots: '@azure/core-util@1.13.1': dependencies: '@azure/abort-controller': 2.1.2 - '@typespec/ts-http-runtime': 0.3.2 + '@typespec/ts-http-runtime': 0.3.7 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -14662,8 +14723,8 @@ snapshots: dependencies: '@azure/abort-controller': 2.1.2 '@azure/core-auth': 1.10.1 - '@azure/core-client': 1.10.1 - '@azure/core-rest-pipeline': 1.22.2 + '@azure/core-client': 1.11.0 + '@azure/core-rest-pipeline': 1.25.0 '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 '@azure/logger': 1.3.0 @@ -14678,8 +14739,8 @@ snapshots: dependencies: '@azure/abort-controller': 1.1.0 '@azure/core-auth': 1.10.1 - '@azure/core-client': 1.10.1 - '@azure/core-rest-pipeline': 1.22.2 + '@azure/core-client': 1.11.0 + '@azure/core-rest-pipeline': 1.25.0 '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 '@azure/logger': 1.3.0 @@ -14697,8 +14758,8 @@ snapshots: dependencies: '@azure/abort-controller': 2.1.2 '@azure/core-auth': 1.10.1 - '@azure/core-client': 1.10.1 - '@azure/core-rest-pipeline': 1.22.2 + '@azure/core-client': 1.11.0 + '@azure/core-rest-pipeline': 1.25.0 '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 '@azure/logger': 1.3.0 @@ -14714,7 +14775,7 @@ snapshots: '@azure/core-http-compat': 2.3.1 '@azure/core-lro': 2.7.2 '@azure/core-paging': 1.6.2 - '@azure/core-rest-pipeline': 1.22.2 + '@azure/core-rest-pipeline': 1.25.0 '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 '@azure/keyvault-common': 2.0.0 @@ -14725,24 +14786,26 @@ snapshots: '@azure/logger@1.3.0': dependencies: - '@typespec/ts-http-runtime': 0.3.2 + '@typespec/ts-http-runtime': 0.3.7 tslib: 2.8.1 transitivePeerDependencies: - supports-color - '@azure/monitor-opentelemetry-exporter@1.0.0-beta.31': + '@azure/monitor-opentelemetry-exporter@1.0.0-beta.43': dependencies: + '@azure-rest/core-client': 2.8.0 '@azure/core-auth': 1.10.1 - '@azure/core-client': 1.10.1 - '@azure/core-rest-pipeline': 1.22.2 + '@azure/core-client': 1.11.0 + '@azure/core-rest-pipeline': 1.25.0 + '@azure/core-util': 1.13.1 '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.57.2 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-logs': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 + '@opentelemetry/api-logs': 0.219.0 + '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.8.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.219.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.8.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.43.0 tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -14750,7 +14813,7 @@ snapshots: '@azure/ms-rest-js@1.11.2': dependencies: '@azure/core-auth': 1.10.1 - axios: 1.16.0 + axios: 1.18.0(supports-color@8.1.1) form-data: 4.0.6 tough-cookie: 4.1.3 tslib: 1.14.1 @@ -14800,11 +14863,11 @@ snapshots: dependencies: '@azure/abort-controller': 2.1.2 '@azure/core-auth': 1.10.1 - '@azure/core-client': 1.10.1 + '@azure/core-client': 1.11.0 '@azure/core-http-compat': 2.3.1 '@azure/core-lro': 2.7.2 '@azure/core-paging': 1.6.2 - '@azure/core-rest-pipeline': 1.22.2 + '@azure/core-rest-pipeline': 1.25.0 '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 '@azure/core-xml': 1.5.1 @@ -14820,7 +14883,7 @@ snapshots: '@azure/abort-controller': 2.1.2 '@azure/core-auth': 1.10.1 '@azure/core-http-compat': 2.3.1 - '@azure/core-rest-pipeline': 1.22.2 + '@azure/core-rest-pipeline': 1.25.0 '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 '@azure/logger': 1.3.0 @@ -14833,10 +14896,10 @@ snapshots: dependencies: '@azure/abort-controller': 2.1.2 '@azure/core-auth': 1.10.1 - '@azure/core-client': 1.10.1 + '@azure/core-client': 1.11.0 '@azure/core-http-compat': 2.3.1 '@azure/core-paging': 1.6.2 - '@azure/core-rest-pipeline': 1.22.2 + '@azure/core-rest-pipeline': 1.25.0 '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 '@azure/core-xml': 1.5.1 @@ -15043,7 +15106,7 @@ snapshots: '@babel/parser@7.29.2': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 '@babel/parser@7.29.7': dependencies: @@ -15625,9 +15688,9 @@ snapshots: '@babel/template@7.28.6': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@babel/template@7.29.7': dependencies: @@ -15760,251 +15823,251 @@ snapshots: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-alpha-function@1.0.1(postcss@8.5.10)': + '@csstools/postcss-alpha-function@1.0.1(postcss@8.5.12)': dependencies: '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - '@csstools/postcss-cascade-layers@5.0.2(postcss@8.5.10)': + '@csstools/postcss-cascade-layers@5.0.2(postcss@8.5.12)': dependencies: '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 7.1.1 - '@csstools/postcss-color-function-display-p3-linear@1.0.1(postcss@8.5.10)': + '@csstools/postcss-color-function-display-p3-linear@1.0.1(postcss@8.5.12)': dependencies: '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - '@csstools/postcss-color-function@4.0.12(postcss@8.5.10)': + '@csstools/postcss-color-function@4.0.12(postcss@8.5.12)': dependencies: '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - '@csstools/postcss-color-mix-function@3.0.12(postcss@8.5.10)': + '@csstools/postcss-color-mix-function@3.0.12(postcss@8.5.12)': dependencies: '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - '@csstools/postcss-color-mix-variadic-function-arguments@1.0.2(postcss@8.5.10)': + '@csstools/postcss-color-mix-variadic-function-arguments@1.0.2(postcss@8.5.12)': dependencies: '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - '@csstools/postcss-content-alt-text@2.0.8(postcss@8.5.10)': + '@csstools/postcss-content-alt-text@2.0.8(postcss@8.5.12)': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - '@csstools/postcss-contrast-color-function@2.0.12(postcss@8.5.10)': + '@csstools/postcss-contrast-color-function@2.0.12(postcss@8.5.12)': dependencies: '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - '@csstools/postcss-exponential-functions@2.0.9(postcss@8.5.10)': + '@csstools/postcss-exponential-functions@2.0.9(postcss@8.5.12)': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - postcss: 8.5.10 + postcss: 8.5.12 - '@csstools/postcss-font-format-keywords@4.0.0(postcss@8.5.10)': + '@csstools/postcss-font-format-keywords@4.0.0(postcss@8.5.12)': dependencies: - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - '@csstools/postcss-gamut-mapping@2.0.11(postcss@8.5.10)': + '@csstools/postcss-gamut-mapping@2.0.11(postcss@8.5.12)': dependencies: '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - postcss: 8.5.10 + postcss: 8.5.12 - '@csstools/postcss-gradients-interpolation-method@5.0.12(postcss@8.5.10)': + '@csstools/postcss-gradients-interpolation-method@5.0.12(postcss@8.5.12)': dependencies: '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - '@csstools/postcss-hwb-function@4.0.12(postcss@8.5.10)': + '@csstools/postcss-hwb-function@4.0.12(postcss@8.5.12)': dependencies: '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - '@csstools/postcss-ic-unit@4.0.4(postcss@8.5.10)': + '@csstools/postcss-ic-unit@4.0.4(postcss@8.5.12)': dependencies: - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - '@csstools/postcss-initial@2.0.1(postcss@8.5.10)': + '@csstools/postcss-initial@2.0.1(postcss@8.5.12)': dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - '@csstools/postcss-is-pseudo-class@5.0.3(postcss@8.5.10)': + '@csstools/postcss-is-pseudo-class@5.0.3(postcss@8.5.12)': dependencies: '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 7.1.1 - '@csstools/postcss-light-dark-function@2.0.11(postcss@8.5.10)': + '@csstools/postcss-light-dark-function@2.0.11(postcss@8.5.12)': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - '@csstools/postcss-logical-float-and-clear@3.0.0(postcss@8.5.10)': + '@csstools/postcss-logical-float-and-clear@3.0.0(postcss@8.5.12)': dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - '@csstools/postcss-logical-overflow@2.0.0(postcss@8.5.10)': + '@csstools/postcss-logical-overflow@2.0.0(postcss@8.5.12)': dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - '@csstools/postcss-logical-overscroll-behavior@2.0.0(postcss@8.5.10)': + '@csstools/postcss-logical-overscroll-behavior@2.0.0(postcss@8.5.12)': dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - '@csstools/postcss-logical-resize@3.0.0(postcss@8.5.10)': + '@csstools/postcss-logical-resize@3.0.0(postcss@8.5.12)': dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - '@csstools/postcss-logical-viewport-units@3.0.4(postcss@8.5.10)': + '@csstools/postcss-logical-viewport-units@3.0.4(postcss@8.5.12)': dependencies: '@csstools/css-tokenizer': 3.0.4 - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - '@csstools/postcss-media-minmax@2.0.9(postcss@8.5.10)': + '@csstools/postcss-media-minmax@2.0.9(postcss@8.5.12)': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - postcss: 8.5.10 + postcss: 8.5.12 - '@csstools/postcss-media-queries-aspect-ratio-number-values@3.0.5(postcss@8.5.10)': + '@csstools/postcss-media-queries-aspect-ratio-number-values@3.0.5(postcss@8.5.12)': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - postcss: 8.5.10 + postcss: 8.5.12 - '@csstools/postcss-nested-calc@4.0.0(postcss@8.5.10)': + '@csstools/postcss-nested-calc@4.0.0(postcss@8.5.12)': dependencies: - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - '@csstools/postcss-normalize-display-values@4.0.0(postcss@8.5.10)': + '@csstools/postcss-normalize-display-values@4.0.0(postcss@8.5.12)': dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - '@csstools/postcss-oklab-function@4.0.12(postcss@8.5.10)': + '@csstools/postcss-oklab-function@4.0.12(postcss@8.5.12)': dependencies: '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - '@csstools/postcss-progressive-custom-properties@4.2.1(postcss@8.5.10)': + '@csstools/postcss-progressive-custom-properties@4.2.1(postcss@8.5.12)': dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - '@csstools/postcss-random-function@2.0.1(postcss@8.5.10)': + '@csstools/postcss-random-function@2.0.1(postcss@8.5.12)': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - postcss: 8.5.10 + postcss: 8.5.12 - '@csstools/postcss-relative-color-syntax@3.0.12(postcss@8.5.10)': + '@csstools/postcss-relative-color-syntax@3.0.12(postcss@8.5.12)': dependencies: '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - '@csstools/postcss-scope-pseudo-class@4.0.1(postcss@8.5.10)': + '@csstools/postcss-scope-pseudo-class@4.0.1(postcss@8.5.12)': dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 7.1.1 - '@csstools/postcss-sign-functions@1.1.4(postcss@8.5.10)': + '@csstools/postcss-sign-functions@1.1.4(postcss@8.5.12)': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - postcss: 8.5.10 + postcss: 8.5.12 - '@csstools/postcss-stepped-value-functions@4.0.9(postcss@8.5.10)': + '@csstools/postcss-stepped-value-functions@4.0.9(postcss@8.5.12)': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - postcss: 8.5.10 + postcss: 8.5.12 - '@csstools/postcss-text-decoration-shorthand@4.0.3(postcss@8.5.10)': + '@csstools/postcss-text-decoration-shorthand@4.0.3(postcss@8.5.12)': dependencies: '@csstools/color-helpers': 5.1.0 - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - '@csstools/postcss-trigonometric-functions@4.0.9(postcss@8.5.10)': + '@csstools/postcss-trigonometric-functions@4.0.9(postcss@8.5.12)': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - postcss: 8.5.10 + postcss: 8.5.12 - '@csstools/postcss-unset-value@4.0.0(postcss@8.5.10)': + '@csstools/postcss-unset-value@4.0.0(postcss@8.5.12)': dependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@csstools/selector-resolve-nested@3.1.0(postcss-selector-parser@7.1.1)': dependencies: @@ -16014,9 +16077,9 @@ snapshots: dependencies: postcss-selector-parser: 7.1.1 - '@csstools/utilities@2.0.0(postcss@8.5.10)': + '@csstools/utilities@2.0.0(postcss@8.5.12)': dependencies: - postcss: 8.5.10 + postcss: 8.5.12 '@ctrl/tinycolor@3.6.1': {} @@ -16274,14 +16337,14 @@ snapshots: copy-webpack-plugin: 11.0.0(webpack@5.105.4(esbuild@0.28.1)) css-loader: 6.11.0(webpack@5.105.4(esbuild@0.28.1)) css-minimizer-webpack-plugin: 5.0.1(clean-css@5.3.3)(esbuild@0.28.1)(webpack@5.105.4(esbuild@0.28.1)) - cssnano: 6.1.2(postcss@8.5.10) + cssnano: 6.1.2(postcss@8.5.12) file-loader: 6.2.0(webpack@5.105.4(esbuild@0.28.1)) html-minifier-terser: 7.2.0 mini-css-extract-plugin: 2.9.4(webpack@5.105.4(esbuild@0.28.1)) null-loader: 4.0.1(webpack@5.105.4(esbuild@0.28.1)) - postcss: 8.5.10 - postcss-loader: 7.3.4(postcss@8.5.10)(typescript@6.0.3)(webpack@5.105.4(esbuild@0.28.1)) - postcss-preset-env: 10.4.0(postcss@8.5.10) + postcss: 8.5.12 + postcss-loader: 7.3.4(postcss@8.5.12)(typescript@6.0.3)(webpack@5.105.4(esbuild@0.28.1)) + postcss-preset-env: 10.4.0(postcss@8.5.12) terser-webpack-plugin: 5.4.0(esbuild@0.28.1)(webpack@5.105.4(esbuild@0.28.1)) tslib: 2.8.1 url-loader: 4.1.1(file-loader@6.2.0(webpack@5.105.4(esbuild@0.28.1)))(webpack@5.105.4(esbuild@0.28.1)) @@ -16366,9 +16429,9 @@ snapshots: '@docusaurus/cssnano-preset@3.10.1': dependencies: - cssnano-preset-advanced: 6.1.2(postcss@8.5.10) - postcss: 8.5.10 - postcss-sort-media-queries: 5.2.0(postcss@8.5.10) + cssnano-preset-advanced: 6.1.2(postcss@8.5.12) + postcss: 8.5.12 + postcss-sort-media-queries: 5.2.0(postcss@8.5.12) tslib: 2.8.1 '@docusaurus/logger@3.10.1': @@ -16791,7 +16854,7 @@ snapshots: infima: 0.2.0-alpha.45 lodash: 4.18.1 nprogress: 0.2.0 - postcss: 8.5.10 + postcss: 8.5.12 prism-react-renderer: 2.4.1(react@19.2.0) prismjs: 1.30.0 react: 19.2.0 @@ -17376,10 +17439,10 @@ snapshots: '@graphql-tools/utils': 10.11.0(graphql@16.12.0) '@whatwg-node/disposablestack': 0.0.6 graphql: 16.12.0 - graphql-ws: 6.0.6(graphql@16.12.0)(ws@8.21.0) - isomorphic-ws: 5.0.0(ws@8.21.0) + graphql-ws: 6.0.6(graphql@16.12.0)(ws@8.21.1) + isomorphic-ws: 5.0.0(ws@8.21.1) tslib: 2.8.1 - ws: 8.21.0 + ws: 8.21.1 transitivePeerDependencies: - '@fastify/websocket' - bufferutil @@ -17407,9 +17470,9 @@ snapshots: '@graphql-tools/utils': 10.11.0(graphql@16.12.0) '@types/ws': 8.18.1 graphql: 16.12.0 - isomorphic-ws: 5.0.0(ws@8.21.0) + isomorphic-ws: 5.0.0(ws@8.21.1) tslib: 2.8.1 - ws: 8.21.0 + ws: 8.21.1 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -17464,10 +17527,10 @@ snapshots: '@graphql-tools/graphql-tag-pluck@8.3.26(graphql@16.12.0)': dependencies: '@babel/core': 7.29.6(supports-color@8.1.1) - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.7 '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.29.6) - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.29.7(supports-color@8.1.1) + '@babel/types': 7.29.7 '@graphql-tools/utils': 10.11.0(graphql@16.12.0) graphql: 16.12.0 tslib: 2.8.1 @@ -17581,10 +17644,10 @@ snapshots: '@whatwg-node/fetch': 0.10.13 '@whatwg-node/promise-helpers': 1.3.2 graphql: 16.12.0 - isomorphic-ws: 5.0.0(ws@8.21.0) + isomorphic-ws: 5.0.0(ws@8.21.1) sync-fetch: 0.6.0-2 tslib: 2.8.1 - ws: 8.21.0 + ws: 8.21.1 transitivePeerDependencies: - '@fastify/websocket' - '@types/node' @@ -17839,6 +17902,14 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs@0.219.0': + dependencies: + '@opentelemetry/api': 1.9.0 + + '@opentelemetry/api-logs@0.220.0': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs@0.52.1': dependencies: '@opentelemetry/api': 1.9.0 @@ -17849,14 +17920,15 @@ snapshots: '@opentelemetry/api@1.9.0': {} - '@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/configuration@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + yaml: 2.8.3 - '@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/context-async-hooks@2.9.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/semantic-conventions': 1.25.1 '@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0)': dependencies: @@ -17873,111 +17945,110 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.38.0 - '@opentelemetry/exporter-logs-otlp-grpc@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.38.0 + + '@opentelemetry/exporter-logs-otlp-grpc@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@grpc/grpc-js': 1.14.4 '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-grpc-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-logs': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-grpc-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.220.0(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-logs-otlp-http@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-logs-otlp-http@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.57.2 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-logs': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/api-logs': 0.220.0 + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.220.0(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-logs-otlp-proto@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-logs-otlp-proto@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.57.2 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-logs': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.220.0(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-grpc@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-metrics-otlp-grpc@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@grpc/grpc-js': 1.14.4 '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-http': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-grpc-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-http': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-grpc-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.9.0(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-http@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-metrics-otlp-http@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.9.0(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-proto@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-metrics-otlp-proto@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-http': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-http': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.9.0(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-prometheus@0.217.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-prometheus@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.38.0 - '@opentelemetry/exporter-trace-otlp-grpc@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-trace-otlp-grpc@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@grpc/grpc-js': 1.14.4 '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-grpc-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-grpc-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace': 2.9.0(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-trace-otlp-http@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-trace-otlp-http@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace': 2.9.0(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-trace-otlp-proto@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-trace-otlp-proto@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace': 2.9.0(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-zipkin@1.30.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/exporter-zipkin@2.9.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.28.0 + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.38.0 '@opentelemetry/instrumentation-dataloader@0.17.0(@opentelemetry/api@1.9.0)': dependencies: @@ -17993,13 +18064,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-http@0.52.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation-http@0.220.0(@opentelemetry/api@1.9.0)(supports-color@8.1.1)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.25.1 - semver: 7.7.3 + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.220.0(@opentelemetry/api@1.9.0)(supports-color@8.1.1) + '@opentelemetry/semantic-conventions': 1.38.0 + forwarded-parse: 2.1.2 transitivePeerDependencies: - supports-color @@ -18023,64 +18094,60 @@ snapshots: transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation@0.220.0(@opentelemetry/api@1.9.0)(supports-color@8.1.1)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.52.1 - '@types/shimmer': 1.2.0 - import-in-the-middle: 1.15.0 - require-in-the-middle: 7.5.2 - semver: 7.7.4 - shimmer: 1.2.1 + '@opentelemetry/api-logs': 0.220.0 + import-in-the-middle: 3.3.1 + require-in-the-middle: 8.0.1(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.57.2 + '@opentelemetry/api-logs': 0.52.1 '@types/shimmer': 1.2.0 import-in-the-middle: 1.15.0 require-in-the-middle: 7.5.2 - semver: 7.7.4 + semver: 7.8.0 shimmer: 1.2.1 transitivePeerDependencies: - supports-color - '@opentelemetry/otlp-exporter-base@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/otlp-exporter-base@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-grpc-exporter-base@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/otlp-grpc-exporter-base@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@grpc/grpc-js': 1.14.4 '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-exporter-base': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer': 0.57.2(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.0) - '@opentelemetry/otlp-transformer@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/otlp-transformer@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.57.2 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-logs': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) - protobufjs: 7.6.5 + '@opentelemetry/api-logs': 0.220.0 + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace': 2.9.0(@opentelemetry/api@1.9.0) - '@opentelemetry/propagator-b3@1.30.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/propagator-b3@2.9.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) - '@opentelemetry/propagator-jaeger@1.30.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/propagator-jaeger@2.9.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources@1.30.1(@opentelemetry/api@1.9.0)': dependencies: @@ -18094,54 +18161,76 @@ snapshots: '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.38.0 - '@opentelemetry/resources@2.7.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/resources@2.8.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.38.0 - '@opentelemetry/sdk-logs@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/resources@2.9.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.57.2 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.38.0 - '@opentelemetry/sdk-metrics@1.30.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/sdk-logs@0.219.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/api-logs': 0.219.0 + '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.8.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.38.0 + + '@opentelemetry/sdk-logs@0.220.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.220.0 + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.38.0 - '@opentelemetry/sdk-metrics@2.7.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/sdk-metrics@2.8.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.8.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-node@0.57.2(@opentelemetry/api@1.9.0)': + '@opentelemetry/sdk-metrics@2.9.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.57.2 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-logs-otlp-grpc': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-logs-otlp-http': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-logs-otlp-proto': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-grpc': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-http': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-metrics-otlp-proto': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-prometheus': 0.217.0(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-trace-otlp-grpc': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-trace-otlp-http': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-trace-otlp-proto': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-zipkin': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-logs': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-metrics': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-node': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.28.0 + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/sdk-node@0.220.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.220.0 + '@opentelemetry/configuration': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/context-async-hooks': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-logs-otlp-grpc': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-logs-otlp-http': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-logs-otlp-proto': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-grpc': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-http': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-metrics-otlp-proto': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-prometheus': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-grpc': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-http': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-proto': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-zipkin': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.220.0(@opentelemetry/api@1.9.0)(supports-color@8.1.1) + '@opentelemetry/otlp-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-grpc-exporter-base': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/propagator-b3': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/propagator-jaeger': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.220.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-node': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -18159,15 +18248,27 @@ snapshots: '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.38.0 - '@opentelemetry/sdk-trace-node@1.30.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/propagator-b3': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/propagator-jaeger': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) - semver: 7.7.4 + '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.8.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.38.0 + + '@opentelemetry/sdk-trace-base@2.9.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.38.0 + + '@opentelemetry/sdk-trace-node@2.9.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-web@2.2.0(@opentelemetry/api@1.9.0)': dependencies: @@ -18175,12 +18276,19 @@ snapshots: '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions@1.25.1': {} + '@opentelemetry/sdk-trace@2.9.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.38.0 '@opentelemetry/semantic-conventions@1.28.0': {} '@opentelemetry/semantic-conventions@1.38.0': {} + '@opentelemetry/semantic-conventions@1.43.0': {} + '@oxc-parser/binding-android-arm-eabi@0.121.0': optional: true @@ -18626,15 +18734,8 @@ snapshots: '@protobufjs/codegen@2.0.5': {} - '@protobufjs/eventemitter@1.1.0': {} - '@protobufjs/eventemitter@1.1.1': {} - '@protobufjs/fetch@1.1.0': - dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/inquire': 1.1.1 - '@protobufjs/fetch@1.1.1': dependencies: '@protobufjs/aspromise': 1.1.2 @@ -19183,7 +19284,7 @@ snapshots: dependencies: '@serenity-js/core': 3.43.0 agent-base: 7.1.4 - axios: 1.16.0 + axios: 1.18.0(supports-color@8.1.1) http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 lru-cache: 11.3.6 @@ -19198,7 +19299,7 @@ snapshots: '@serenity-js/core': 3.43.0 '@serenity-js/rest': 3.43.0 ansi-regex: 5.0.1 - axios: 1.16.0 + axios: 1.18.0(supports-color@8.1.1) chalk: 4.1.2 find-java-home: 2.0.0 progress: 2.0.3 @@ -19248,10 +19349,10 @@ snapshots: color: 5.0.3 text-hex: 1.0.0 - '@sonar/scan@4.3.2': + '@sonar/scan@4.3.2(supports-color@8.1.1)': dependencies: adm-zip: 0.5.16 - axios: 1.16.0 + axios: 1.18.0(supports-color@8.1.1) commander: 13.1.0 fs-extra: 11.3.2 hpagent: 1.2.0 @@ -19265,6 +19366,7 @@ snapshots: - bare-abort-controller - debug - react-native-b4a + - supports-color '@standard-schema/spec@1.1.0': {} @@ -19297,16 +19399,16 @@ snapshots: dependencies: storybook: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@storybook/addon-vitest@10.4.2(@vitest/browser-playwright@4.1.8)(@vitest/browser@4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8))(@vitest/runner@4.1.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.8)': + '@storybook/addon-vitest@10.4.2(@vitest/browser-playwright@4.1.10)(@vitest/browser@4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10))(@vitest/runner@4.1.10)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vitest@4.1.10)': dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) storybook: 10.4.2(@testing-library/dom@10.4.1)(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) optionalDependencies: - '@vitest/browser': 4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8) - '@vitest/browser-playwright': 4.1.8(playwright@1.59.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8) - '@vitest/runner': 4.1.8 - vitest: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/browser': 4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10) + '@vitest/browser-playwright': 4.1.10(playwright@1.59.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10) + '@vitest/runner': 4.1.10 + vitest: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) transitivePeerDependencies: - react - react-dom @@ -19462,7 +19564,7 @@ snapshots: '@svgr/core': 8.1.0(typescript@6.0.3) cosmiconfig: 8.3.6(typescript@6.0.3) deepmerge: 4.3.1 - svgo: 3.3.3 + svgo: 3.3.4 transitivePeerDependencies: - typescript @@ -19845,7 +19947,7 @@ snapshots: '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260428.1 '@typescript/native-preview-win32-x64': 7.0.0-dev.20260428.1 - '@typespec/ts-http-runtime@0.3.2': + '@typespec/ts-http-runtime@0.3.7': dependencies: http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 @@ -19868,13 +19970,13 @@ snapshots: '@rolldown/pluginutils': 1.0.0-rc.7 vite: 8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) - '@vitest/browser-playwright@4.1.8(playwright@1.59.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8)': + '@vitest/browser-playwright@4.1.10(playwright@1.59.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10)': dependencies: - '@vitest/browser': 4.1.8(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8) - '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/browser': 4.1.10(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10) + '@vitest/mocker': 4.1.10(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) playwright: 1.59.0 tinyrainbow: 3.1.0 - vitest: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + vitest: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) transitivePeerDependencies: - bufferutil - msw @@ -19882,30 +19984,30 @@ snapshots: - vite optional: true - '@vitest/browser-playwright@4.1.8(playwright@1.59.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8)': + '@vitest/browser-playwright@4.1.10(playwright@1.59.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10)': dependencies: - '@vitest/browser': 4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8) - '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/browser': 4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10) + '@vitest/mocker': 4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) playwright: 1.59.0 tinyrainbow: 3.1.0 - vitest: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + vitest: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/browser@4.1.8(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8)': + '@vitest/browser@4.1.10(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10)': dependencies: '@blazediff/core': 1.9.1 - '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) - '@vitest/utils': 4.1.8 + '@vitest/mocker': 4.1.10(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/utils': 4.1.10 magic-string: 0.30.21 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.0 - vitest: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) - ws: 8.21.0 + vitest: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + ws: 8.21.1 transitivePeerDependencies: - bufferutil - msw @@ -19913,24 +20015,24 @@ snapshots: - vite optional: true - '@vitest/browser@4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8)': + '@vitest/browser@4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10)': dependencies: '@blazediff/core': 1.9.1 - '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) - '@vitest/utils': 4.1.8 + '@vitest/mocker': 4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/utils': 4.1.10 magic-string: 0.30.21 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.0 - vitest: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) - ws: 8.21.0 + vitest: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + ws: 8.21.1 transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/coverage-istanbul@4.1.8(supports-color@8.1.1)(vitest@4.1.8)': + '@vitest/coverage-istanbul@4.1.10(supports-color@8.1.1)(vitest@4.1.10)': dependencies: '@babel/core': 7.29.6(supports-color@8.1.1) '@istanbuljs/schema': 0.1.3 @@ -19942,11 +20044,11 @@ snapshots: magicast: 0.5.2 obug: 2.1.1 tinyrainbow: 3.1.0 - vitest: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + vitest: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) transitivePeerDependencies: - supports-color - '@vitest/coverage-istanbul@4.1.8(vitest@4.1.8)': + '@vitest/coverage-istanbul@4.1.10(vitest@4.1.10)': dependencies: '@babel/core': 7.29.6(supports-color@8.1.1) '@istanbuljs/schema': 0.1.3 @@ -19958,7 +20060,7 @@ snapshots: magicast: 0.5.2 obug: 2.1.1 tinyrainbow: 3.1.0 - vitest: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + vitest: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) transitivePeerDependencies: - supports-color @@ -19970,26 +20072,26 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/expect@4.1.8': + '@vitest/expect@4.1.10': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.8 - '@vitest/utils': 4.1.8 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.8(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': + '@vitest/mocker@4.1.10(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: - '@vitest/spy': 4.1.8 + '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: vite: 8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) - '@vitest/mocker@4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': + '@vitest/mocker@4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: - '@vitest/spy': 4.1.8 + '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: @@ -19999,19 +20101,19 @@ snapshots: dependencies: tinyrainbow: 2.0.0 - '@vitest/pretty-format@4.1.8': + '@vitest/pretty-format@4.1.10': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.8': + '@vitest/runner@4.1.10': dependencies: - '@vitest/utils': 4.1.8 + '@vitest/utils': 4.1.10 pathe: 2.0.3 - '@vitest/snapshot@4.1.8': + '@vitest/snapshot@4.1.10': dependencies: - '@vitest/pretty-format': 4.1.8 - '@vitest/utils': 4.1.8 + '@vitest/pretty-format': 4.1.10 + '@vitest/utils': 4.1.10 magic-string: 0.30.21 pathe: 2.0.3 @@ -20019,7 +20121,7 @@ snapshots: dependencies: tinyspy: 4.0.4 - '@vitest/spy@4.1.8': {} + '@vitest/spy@4.1.10': {} '@vitest/utils@3.2.4': dependencies: @@ -20027,9 +20129,9 @@ snapshots: loupe: 3.2.1 tinyrainbow: 2.0.0 - '@vitest/utils@4.1.8': + '@vitest/utils@4.1.10': dependencies: - '@vitest/pretty-format': 4.1.8 + '@vitest/pretty-format': 4.1.10 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 @@ -20188,6 +20290,12 @@ snapshots: adm-zip@0.5.16: {} + agent-base@6.0.2(supports-color@8.1.1): + dependencies: + debug: 4.4.3(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + agent-base@7.1.4: {} aggregate-error@3.1.0: @@ -20226,7 +20334,7 @@ snapshots: ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 4.0.1 + fast-uri: 4.1.1 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -20346,9 +20454,9 @@ snapshots: normalize-path: 3.0.0 picomatch: 4.0.4 - apollo-link-rest@0.9.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(qs@6.15.2): + apollo-link-rest@0.9.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(qs@6.15.2): dependencies: - '@apollo/client': 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@apollo/client': 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) graphql: 16.12.0 qs: 6.15.2 @@ -20372,7 +20480,7 @@ snapshots: archunit@2.1.63: dependencies: '@zerollup/ts-helpers': 1.7.18(typescript@5.9.3) - minimatch: 10.2.4 + minimatch: 10.2.5 plantuml-parser: 0.4.0 typescript: 5.9.3 @@ -20481,14 +20589,14 @@ snapshots: auto-bind@4.0.0: {} - autoprefixer@10.4.22(postcss@8.5.10): + autoprefixer@10.4.22(postcss@8.5.12): dependencies: browserslist: 4.28.1 caniuse-lite: 1.0.30001777 fraction.js: 5.3.4 normalize-range: 0.1.2 picocolors: 1.1.1 - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: @@ -20499,20 +20607,22 @@ snapshots: axe-core@4.11.0: {} - axios@1.16.0: + axios@1.18.0(supports-color@8.1.1): dependencies: follow-redirects: 1.16.0(debug@4.4.3) form-data: 4.0.6 + https-proxy-agent: 5.0.1(supports-color@8.1.1) proxy-from-env: 2.1.0 transitivePeerDependencies: - debug + - supports-color azurite@3.35.0(supports-color@8.1.1): dependencies: '@azure/ms-rest-js': 1.11.2 applicationinsights: 2.9.8 args: 5.0.3 - axios: 1.16.0 + axios: 1.18.0(supports-color@8.1.1) etag: 1.8.1 express: 4.22.2 fs-extra: 11.3.2 @@ -20559,7 +20669,7 @@ snapshots: babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.29.6): dependencies: - '@babel/compat-data': 7.29.0 + '@babel/compat-data': 7.29.7 '@babel/core': 7.29.6(supports-color@8.1.1) '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.29.6) semver: 6.3.1 @@ -20964,7 +21074,7 @@ snapshots: chromatic@16.10.0: dependencies: - semver: 7.7.4 + semver: 7.8.0 chrome-devtools-mcp@1.3.0: {} @@ -20980,6 +21090,8 @@ snapshots: cjs-module-lexer@1.4.3: {} + cjs-module-lexer@2.2.0: {} + class-transformer@0.5.1: {} classnames@2.5.1: {} @@ -21282,41 +21394,41 @@ snapshots: dependencies: type-fest: 1.4.0 - css-blank-pseudo@7.0.1(postcss@8.5.10): + css-blank-pseudo@7.0.1(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 7.1.1 - css-declaration-sorter@7.3.0(postcss@8.5.10): + css-declaration-sorter@7.3.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - css-has-pseudo@7.0.3(postcss@8.5.10): + css-has-pseudo@7.0.3(postcss@8.5.12): dependencies: '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 css-loader@6.11.0(webpack@5.105.4(esbuild@0.28.1)): dependencies: - icss-utils: 5.1.0(postcss@8.5.10) - postcss: 8.5.10 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.10) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.10) - postcss-modules-scope: 3.2.1(postcss@8.5.10) - postcss-modules-values: 4.0.0(postcss@8.5.10) + icss-utils: 5.1.0(postcss@8.5.12) + postcss: 8.5.12 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.12) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.12) + postcss-modules-scope: 3.2.1(postcss@8.5.12) + postcss-modules-values: 4.0.0(postcss@8.5.12) postcss-value-parser: 4.2.0 - semver: 7.7.4 + semver: 7.8.0 optionalDependencies: webpack: 5.105.4(esbuild@0.28.1) css-minimizer-webpack-plugin@5.0.1(clean-css@5.3.3)(esbuild@0.28.1)(webpack@5.105.4(esbuild@0.28.1)): dependencies: '@jridgewell/trace-mapping': 0.3.31 - cssnano: 6.1.2(postcss@8.5.10) + cssnano: 6.1.2(postcss@8.5.12) jest-worker: 29.7.0 - postcss: 8.5.10 + postcss: 8.5.12 schema-utils: 4.3.3 serialize-javascript: 7.0.5 webpack: 5.105.4(esbuild@0.28.1) @@ -21324,9 +21436,9 @@ snapshots: clean-css: 5.3.3 esbuild: 0.28.1 - css-prefers-color-scheme@10.0.0(postcss@8.5.10): + css-prefers-color-scheme@10.0.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 css-select@4.3.0: dependencies: @@ -21362,60 +21474,60 @@ snapshots: cssesc@3.0.0: {} - cssnano-preset-advanced@6.1.2(postcss@8.5.10): + cssnano-preset-advanced@6.1.2(postcss@8.5.12): dependencies: - autoprefixer: 10.4.22(postcss@8.5.10) + autoprefixer: 10.4.22(postcss@8.5.12) browserslist: 4.28.1 - cssnano-preset-default: 6.1.2(postcss@8.5.10) - postcss: 8.5.10 - postcss-discard-unused: 6.0.5(postcss@8.5.10) - postcss-merge-idents: 6.0.3(postcss@8.5.10) - postcss-reduce-idents: 6.0.3(postcss@8.5.10) - postcss-zindex: 6.0.2(postcss@8.5.10) + cssnano-preset-default: 6.1.2(postcss@8.5.12) + postcss: 8.5.12 + postcss-discard-unused: 6.0.5(postcss@8.5.12) + postcss-merge-idents: 6.0.3(postcss@8.5.12) + postcss-reduce-idents: 6.0.3(postcss@8.5.12) + postcss-zindex: 6.0.2(postcss@8.5.12) - cssnano-preset-default@6.1.2(postcss@8.5.10): + cssnano-preset-default@6.1.2(postcss@8.5.12): dependencies: browserslist: 4.28.1 - css-declaration-sorter: 7.3.0(postcss@8.5.10) - cssnano-utils: 4.0.2(postcss@8.5.10) - postcss: 8.5.10 - postcss-calc: 9.0.1(postcss@8.5.10) - postcss-colormin: 6.1.0(postcss@8.5.10) - postcss-convert-values: 6.1.0(postcss@8.5.10) - postcss-discard-comments: 6.0.2(postcss@8.5.10) - postcss-discard-duplicates: 6.0.3(postcss@8.5.10) - postcss-discard-empty: 6.0.3(postcss@8.5.10) - postcss-discard-overridden: 6.0.2(postcss@8.5.10) - postcss-merge-longhand: 6.0.5(postcss@8.5.10) - postcss-merge-rules: 6.1.1(postcss@8.5.10) - postcss-minify-font-values: 6.1.0(postcss@8.5.10) - postcss-minify-gradients: 6.0.3(postcss@8.5.10) - postcss-minify-params: 6.1.0(postcss@8.5.10) - postcss-minify-selectors: 6.0.4(postcss@8.5.10) - postcss-normalize-charset: 6.0.2(postcss@8.5.10) - postcss-normalize-display-values: 6.0.2(postcss@8.5.10) - postcss-normalize-positions: 6.0.2(postcss@8.5.10) - postcss-normalize-repeat-style: 6.0.2(postcss@8.5.10) - postcss-normalize-string: 6.0.2(postcss@8.5.10) - postcss-normalize-timing-functions: 6.0.2(postcss@8.5.10) - postcss-normalize-unicode: 6.1.0(postcss@8.5.10) - postcss-normalize-url: 6.0.2(postcss@8.5.10) - postcss-normalize-whitespace: 6.0.2(postcss@8.5.10) - postcss-ordered-values: 6.0.2(postcss@8.5.10) - postcss-reduce-initial: 6.1.0(postcss@8.5.10) - postcss-reduce-transforms: 6.0.2(postcss@8.5.10) - postcss-svgo: 6.0.3(postcss@8.5.10) - postcss-unique-selectors: 6.0.4(postcss@8.5.10) - - cssnano-utils@4.0.2(postcss@8.5.10): - dependencies: - postcss: 8.5.10 - - cssnano@6.1.2(postcss@8.5.10): - dependencies: - cssnano-preset-default: 6.1.2(postcss@8.5.10) + css-declaration-sorter: 7.3.0(postcss@8.5.12) + cssnano-utils: 4.0.2(postcss@8.5.12) + postcss: 8.5.12 + postcss-calc: 9.0.1(postcss@8.5.12) + postcss-colormin: 6.1.0(postcss@8.5.12) + postcss-convert-values: 6.1.0(postcss@8.5.12) + postcss-discard-comments: 6.0.2(postcss@8.5.12) + postcss-discard-duplicates: 6.0.3(postcss@8.5.12) + postcss-discard-empty: 6.0.3(postcss@8.5.12) + postcss-discard-overridden: 6.0.2(postcss@8.5.12) + postcss-merge-longhand: 6.0.5(postcss@8.5.12) + postcss-merge-rules: 6.1.1(postcss@8.5.12) + postcss-minify-font-values: 6.1.0(postcss@8.5.12) + postcss-minify-gradients: 6.0.3(postcss@8.5.12) + postcss-minify-params: 6.1.0(postcss@8.5.12) + postcss-minify-selectors: 6.0.4(postcss@8.5.12) + postcss-normalize-charset: 6.0.2(postcss@8.5.12) + postcss-normalize-display-values: 6.0.2(postcss@8.5.12) + postcss-normalize-positions: 6.0.2(postcss@8.5.12) + postcss-normalize-repeat-style: 6.0.2(postcss@8.5.12) + postcss-normalize-string: 6.0.2(postcss@8.5.12) + postcss-normalize-timing-functions: 6.0.2(postcss@8.5.12) + postcss-normalize-unicode: 6.1.0(postcss@8.5.12) + postcss-normalize-url: 6.0.2(postcss@8.5.12) + postcss-normalize-whitespace: 6.0.2(postcss@8.5.12) + postcss-ordered-values: 6.0.2(postcss@8.5.12) + postcss-reduce-initial: 6.1.0(postcss@8.5.12) + postcss-reduce-transforms: 6.0.2(postcss@8.5.12) + postcss-svgo: 6.0.3(postcss@8.5.12) + postcss-unique-selectors: 6.0.4(postcss@8.5.12) + + cssnano-utils@4.0.2(postcss@8.5.12): + dependencies: + postcss: 8.5.12 + + cssnano@6.1.2(postcss@8.5.12): + dependencies: + cssnano-preset-default: 6.1.2(postcss@8.5.12) lilconfig: 3.1.3 - postcss: 8.5.10 + postcss: 8.5.12 csso@5.0.5: dependencies: @@ -21799,7 +21911,7 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@2.0.0: {} + es-module-lexer@2.3.1: {} es-object-atoms@1.1.1: dependencies: @@ -21810,7 +21922,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 - hasown: 2.0.2 + hasown: 2.0.4 es-to-primitive@1.3.0: dependencies: @@ -22051,7 +22163,7 @@ snapshots: fast-json-stable-stringify@2.1.0: {} - fast-uri@4.0.1: {} + fast-uri@4.1.1: {} fast-xml-builder@1.2.0: dependencies: @@ -22076,7 +22188,7 @@ snapshots: faye-websocket@0.11.4: dependencies: - websocket-driver: 0.7.4 + websocket-driver: 0.7.5 fb-watchman@2.0.2: dependencies: @@ -22238,6 +22350,8 @@ snapshots: dependencies: fetch-blob: 3.2.0 + forwarded-parse@2.1.2: {} + forwarded@0.2.0: {} fraction.js@5.3.4: {} @@ -22349,20 +22463,20 @@ snapshots: dependencies: foreground-child: 3.3.1 jackspeak: 4.1.1 - minimatch: 10.2.4 + minimatch: 10.2.5 minipass: 7.1.3 package-json-from-dist: 1.0.1 path-scurry: 2.0.2 glob@13.0.0: dependencies: - minimatch: 10.2.4 + minimatch: 10.2.5 minipass: 7.1.3 path-scurry: 2.0.2 glob@13.0.6: dependencies: - minimatch: 10.2.4 + minimatch: 10.2.5 minipass: 7.1.3 path-scurry: 2.0.2 @@ -22381,7 +22495,7 @@ snapshots: es6-error: 4.1.1 matcher: 3.0.0 roarr: 2.15.4 - semver: 7.7.4 + semver: 7.8.0 serialize-error: 7.0.1 global-dirs@3.0.1: @@ -22492,11 +22606,11 @@ snapshots: graphql: 16.12.0 tslib: 2.8.1 - graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0): + graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1): dependencies: graphql: 16.12.0 optionalDependencies: - ws: 8.21.0 + ws: 8.21.1 graphql@14.7.0: dependencies: @@ -22525,7 +22639,7 @@ snapshots: buffer-image-size: 0.6.4 entities: 7.0.1 whatwg-mimetype: 3.0.0 - ws: 8.21.0 + ws: 8.21.1 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -22573,10 +22687,6 @@ snapshots: inherits: 2.0.4 minimalistic-assert: 1.0.1 - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - hasown@2.0.4: dependencies: function-bind: 1.1.2 @@ -22830,6 +22940,13 @@ snapshots: https-browserify@1.0.0: {} + https-proxy-agent@5.0.1(supports-color@8.1.1): + dependencies: + agent-base: 6.0.2(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 @@ -22857,9 +22974,9 @@ snapshots: dependencies: safer-buffer: 2.1.2 - icss-utils@5.1.0(postcss@8.5.10): + icss-utils@5.1.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 ieee754@1.2.1: {} @@ -22890,6 +23007,12 @@ snapshots: cjs-module-lexer: 1.4.3 module-details-from-path: 1.0.4 + import-in-the-middle@3.3.1: + dependencies: + cjs-module-lexer: 2.2.0 + es-module-lexer: 2.3.1 + module-details-from-path: 1.0.4 + import-lazy@4.0.0: {} imurmurhash@0.1.4: {} @@ -23007,7 +23130,7 @@ snapshots: is-core-module@2.16.1: dependencies: - hasown: 2.0.2 + hasown: 2.0.4 is-data-view@1.0.2: dependencies: @@ -23196,9 +23319,9 @@ snapshots: isomorphic-timers-promises@1.0.1: {} - isomorphic-ws@5.0.0(ws@8.21.0): + isomorphic-ws@5.0.0(ws@8.21.1): dependencies: - ws: 8.21.0 + ws: 8.21.1 istanbul-lib-coverage@3.2.2: {} @@ -23294,7 +23417,7 @@ snapshots: whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.2.0 - ws: 8.21.0 + ws: 8.21.1 xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil @@ -23617,8 +23740,6 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.3.5: {} - lru-cache@11.3.6: {} lru-cache@5.1.1: @@ -23639,8 +23760,8 @@ snapshots: magicast@0.5.2: dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 source-map-js: 1.2.1 make-dir@2.1.0: @@ -23655,7 +23776,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.4 + semver: 7.8.0 map-cache@0.2.2: {} @@ -24241,10 +24362,6 @@ snapshots: minimalistic-crypto-utils@1.0.1: {} - minimatch@10.2.4: - dependencies: - brace-expansion: 5.0.7 - minimatch@10.2.5: dependencies: brace-expansion: 5.0.7 @@ -24286,7 +24403,7 @@ snapshots: https-proxy-agent: 7.0.6 mongodb: 6.21.0 new-find-package-json: 2.0.0(supports-color@8.1.1) - semver: 7.7.4 + semver: 7.8.0 tar-stream: 3.1.7 tslib: 2.8.1 yauzl: 3.2.1 @@ -24312,7 +24429,7 @@ snapshots: https-proxy-agent: 7.0.6 mongodb: 6.21.0 new-find-package-json: 2.0.0(supports-color@8.1.1) - semver: 7.7.4 + semver: 7.8.0 tar-stream: 3.1.7 tslib: 2.8.1 yauzl: 3.2.1 @@ -24952,7 +25069,7 @@ snapshots: path-scurry@2.0.2: dependencies: - lru-cache: 11.3.5 + lru-cache: 11.3.6 minipass: 7.1.3 path-to-regexp@0.1.13: {} @@ -25046,429 +25163,429 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-attribute-case-insensitive@7.0.1(postcss@8.5.10): + postcss-attribute-case-insensitive@7.0.1(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 7.1.1 - postcss-calc@9.0.1(postcss@8.5.10): + postcss-calc@9.0.1(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 - postcss-clamp@4.1.0(postcss@8.5.10): + postcss-clamp@4.1.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-color-functional-notation@7.0.12(postcss@8.5.10): + postcss-color-functional-notation@7.0.12(postcss@8.5.12): dependencies: '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - postcss-color-hex-alpha@10.0.0(postcss@8.5.10): + postcss-color-hex-alpha@10.0.0(postcss@8.5.12): dependencies: - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-color-rebeccapurple@10.0.0(postcss@8.5.10): + postcss-color-rebeccapurple@10.0.0(postcss@8.5.12): dependencies: - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-colormin@6.1.0(postcss@8.5.10): + postcss-colormin@6.1.0(postcss@8.5.12): dependencies: browserslist: 4.28.1 caniuse-api: 3.0.0 colord: 2.9.3 - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-convert-values@6.1.0(postcss@8.5.10): + postcss-convert-values@6.1.0(postcss@8.5.12): dependencies: browserslist: 4.28.1 - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-custom-media@11.0.6(postcss@8.5.10): + postcss-custom-media@11.0.6(postcss@8.5.12): dependencies: '@csstools/cascade-layer-name-parser': 2.0.5(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - postcss: 8.5.10 + postcss: 8.5.12 - postcss-custom-properties@14.0.6(postcss@8.5.10): + postcss-custom-properties@14.0.6(postcss@8.5.12): dependencies: '@csstools/cascade-layer-name-parser': 2.0.5(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-custom-selectors@8.0.5(postcss@8.5.10): + postcss-custom-selectors@8.0.5(postcss@8.5.12): dependencies: '@csstools/cascade-layer-name-parser': 2.0.5(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 7.1.1 - postcss-dir-pseudo-class@9.0.1(postcss@8.5.10): + postcss-dir-pseudo-class@9.0.1(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 7.1.1 - postcss-discard-comments@6.0.2(postcss@8.5.10): + postcss-discard-comments@6.0.2(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - postcss-discard-duplicates@6.0.3(postcss@8.5.10): + postcss-discard-duplicates@6.0.3(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - postcss-discard-empty@6.0.3(postcss@8.5.10): + postcss-discard-empty@6.0.3(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - postcss-discard-overridden@6.0.2(postcss@8.5.10): + postcss-discard-overridden@6.0.2(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - postcss-discard-unused@6.0.5(postcss@8.5.10): + postcss-discard-unused@6.0.5(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 6.1.2 - postcss-double-position-gradients@6.0.4(postcss@8.5.10): + postcss-double-position-gradients@6.0.4(postcss@8.5.12): dependencies: - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-focus-visible@10.0.1(postcss@8.5.10): + postcss-focus-visible@10.0.1(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 7.1.1 - postcss-focus-within@9.0.1(postcss@8.5.10): + postcss-focus-within@9.0.1(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 7.1.1 - postcss-font-variant@5.0.0(postcss@8.5.10): + postcss-font-variant@5.0.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - postcss-gap-properties@6.0.0(postcss@8.5.10): + postcss-gap-properties@6.0.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - postcss-image-set-function@7.0.0(postcss@8.5.10): + postcss-image-set-function@7.0.0(postcss@8.5.12): dependencies: - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-import@15.1.0(postcss@8.5.10): + postcss-import@15.1.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.11 - postcss-js@4.1.0(postcss@8.5.10): + postcss-js@4.1.0(postcss@8.5.12): dependencies: camelcase-css: 2.0.1 - postcss: 8.5.10 + postcss: 8.5.12 - postcss-lab-function@7.0.12(postcss@8.5.10): + postcss-lab-function@7.0.12(postcss@8.5.12): dependencies: '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/utilities': 2.0.0(postcss@8.5.10) - postcss: 8.5.10 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/utilities': 2.0.0(postcss@8.5.12) + postcss: 8.5.12 - postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(yaml@2.8.3): + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.12)(tsx@4.21.0)(yaml@2.8.3): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.6.1 - postcss: 8.5.10 + postcss: 8.5.12 tsx: 4.21.0 yaml: 2.8.3 - postcss-loader@7.3.4(postcss@8.5.10)(typescript@6.0.3)(webpack@5.105.4(esbuild@0.28.1)): + postcss-loader@7.3.4(postcss@8.5.12)(typescript@6.0.3)(webpack@5.105.4(esbuild@0.28.1)): dependencies: cosmiconfig: 8.3.6(typescript@6.0.3) jiti: 2.6.1 - postcss: 8.5.10 - semver: 7.7.4 + postcss: 8.5.12 + semver: 7.8.0 webpack: 5.105.4(esbuild@0.28.1) transitivePeerDependencies: - typescript - postcss-logical@8.1.0(postcss@8.5.10): + postcss-logical@8.1.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-merge-idents@6.0.3(postcss@8.5.10): + postcss-merge-idents@6.0.3(postcss@8.5.12): dependencies: - cssnano-utils: 4.0.2(postcss@8.5.10) - postcss: 8.5.10 + cssnano-utils: 4.0.2(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-merge-longhand@6.0.5(postcss@8.5.10): + postcss-merge-longhand@6.0.5(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - stylehacks: 6.1.1(postcss@8.5.10) + stylehacks: 6.1.1(postcss@8.5.12) - postcss-merge-rules@6.1.1(postcss@8.5.10): + postcss-merge-rules@6.1.1(postcss@8.5.12): dependencies: browserslist: 4.28.1 caniuse-api: 3.0.0 - cssnano-utils: 4.0.2(postcss@8.5.10) - postcss: 8.5.10 + cssnano-utils: 4.0.2(postcss@8.5.12) + postcss: 8.5.12 postcss-selector-parser: 6.1.2 - postcss-minify-font-values@6.1.0(postcss@8.5.10): + postcss-minify-font-values@6.1.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-minify-gradients@6.0.3(postcss@8.5.10): + postcss-minify-gradients@6.0.3(postcss@8.5.12): dependencies: colord: 2.9.3 - cssnano-utils: 4.0.2(postcss@8.5.10) - postcss: 8.5.10 + cssnano-utils: 4.0.2(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-minify-params@6.1.0(postcss@8.5.10): + postcss-minify-params@6.1.0(postcss@8.5.12): dependencies: browserslist: 4.28.1 - cssnano-utils: 4.0.2(postcss@8.5.10) - postcss: 8.5.10 + cssnano-utils: 4.0.2(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-minify-selectors@6.0.4(postcss@8.5.10): + postcss-minify-selectors@6.0.4(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 6.1.2 - postcss-modules-extract-imports@3.1.0(postcss@8.5.10): + postcss-modules-extract-imports@3.1.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - postcss-modules-local-by-default@4.2.0(postcss@8.5.10): + postcss-modules-local-by-default@4.2.0(postcss@8.5.12): dependencies: - icss-utils: 5.1.0(postcss@8.5.10) - postcss: 8.5.10 + icss-utils: 5.1.0(postcss@8.5.12) + postcss: 8.5.12 postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 - postcss-modules-scope@3.2.1(postcss@8.5.10): + postcss-modules-scope@3.2.1(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 7.1.1 - postcss-modules-values@4.0.0(postcss@8.5.10): + postcss-modules-values@4.0.0(postcss@8.5.12): dependencies: - icss-utils: 5.1.0(postcss@8.5.10) - postcss: 8.5.10 + icss-utils: 5.1.0(postcss@8.5.12) + postcss: 8.5.12 - postcss-nested@6.2.0(postcss@8.5.10): + postcss-nested@6.2.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 6.1.2 - postcss-nesting@13.0.2(postcss@8.5.10): + postcss-nesting@13.0.2(postcss@8.5.12): dependencies: '@csstools/selector-resolve-nested': 3.1.0(postcss-selector-parser@7.1.1) '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 7.1.1 - postcss-normalize-charset@6.0.2(postcss@8.5.10): + postcss-normalize-charset@6.0.2(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - postcss-normalize-display-values@6.0.2(postcss@8.5.10): + postcss-normalize-display-values@6.0.2(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-normalize-positions@6.0.2(postcss@8.5.10): + postcss-normalize-positions@6.0.2(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-normalize-repeat-style@6.0.2(postcss@8.5.10): + postcss-normalize-repeat-style@6.0.2(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-normalize-string@6.0.2(postcss@8.5.10): + postcss-normalize-string@6.0.2(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-normalize-timing-functions@6.0.2(postcss@8.5.10): + postcss-normalize-timing-functions@6.0.2(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-normalize-unicode@6.1.0(postcss@8.5.10): + postcss-normalize-unicode@6.1.0(postcss@8.5.12): dependencies: browserslist: 4.28.1 - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-normalize-url@6.0.2(postcss@8.5.10): + postcss-normalize-url@6.0.2(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-normalize-whitespace@6.0.2(postcss@8.5.10): + postcss-normalize-whitespace@6.0.2(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-opacity-percentage@3.0.0(postcss@8.5.10): + postcss-opacity-percentage@3.0.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - postcss-ordered-values@6.0.2(postcss@8.5.10): + postcss-ordered-values@6.0.2(postcss@8.5.12): dependencies: - cssnano-utils: 4.0.2(postcss@8.5.10) - postcss: 8.5.10 + cssnano-utils: 4.0.2(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-overflow-shorthand@6.0.0(postcss@8.5.10): + postcss-overflow-shorthand@6.0.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-page-break@3.0.4(postcss@8.5.10): + postcss-page-break@3.0.4(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - postcss-place@10.0.0(postcss@8.5.10): + postcss-place@10.0.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-preset-env@10.4.0(postcss@8.5.10): - dependencies: - '@csstools/postcss-alpha-function': 1.0.1(postcss@8.5.10) - '@csstools/postcss-cascade-layers': 5.0.2(postcss@8.5.10) - '@csstools/postcss-color-function': 4.0.12(postcss@8.5.10) - '@csstools/postcss-color-function-display-p3-linear': 1.0.1(postcss@8.5.10) - '@csstools/postcss-color-mix-function': 3.0.12(postcss@8.5.10) - '@csstools/postcss-color-mix-variadic-function-arguments': 1.0.2(postcss@8.5.10) - '@csstools/postcss-content-alt-text': 2.0.8(postcss@8.5.10) - '@csstools/postcss-contrast-color-function': 2.0.12(postcss@8.5.10) - '@csstools/postcss-exponential-functions': 2.0.9(postcss@8.5.10) - '@csstools/postcss-font-format-keywords': 4.0.0(postcss@8.5.10) - '@csstools/postcss-gamut-mapping': 2.0.11(postcss@8.5.10) - '@csstools/postcss-gradients-interpolation-method': 5.0.12(postcss@8.5.10) - '@csstools/postcss-hwb-function': 4.0.12(postcss@8.5.10) - '@csstools/postcss-ic-unit': 4.0.4(postcss@8.5.10) - '@csstools/postcss-initial': 2.0.1(postcss@8.5.10) - '@csstools/postcss-is-pseudo-class': 5.0.3(postcss@8.5.10) - '@csstools/postcss-light-dark-function': 2.0.11(postcss@8.5.10) - '@csstools/postcss-logical-float-and-clear': 3.0.0(postcss@8.5.10) - '@csstools/postcss-logical-overflow': 2.0.0(postcss@8.5.10) - '@csstools/postcss-logical-overscroll-behavior': 2.0.0(postcss@8.5.10) - '@csstools/postcss-logical-resize': 3.0.0(postcss@8.5.10) - '@csstools/postcss-logical-viewport-units': 3.0.4(postcss@8.5.10) - '@csstools/postcss-media-minmax': 2.0.9(postcss@8.5.10) - '@csstools/postcss-media-queries-aspect-ratio-number-values': 3.0.5(postcss@8.5.10) - '@csstools/postcss-nested-calc': 4.0.0(postcss@8.5.10) - '@csstools/postcss-normalize-display-values': 4.0.0(postcss@8.5.10) - '@csstools/postcss-oklab-function': 4.0.12(postcss@8.5.10) - '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.10) - '@csstools/postcss-random-function': 2.0.1(postcss@8.5.10) - '@csstools/postcss-relative-color-syntax': 3.0.12(postcss@8.5.10) - '@csstools/postcss-scope-pseudo-class': 4.0.1(postcss@8.5.10) - '@csstools/postcss-sign-functions': 1.1.4(postcss@8.5.10) - '@csstools/postcss-stepped-value-functions': 4.0.9(postcss@8.5.10) - '@csstools/postcss-text-decoration-shorthand': 4.0.3(postcss@8.5.10) - '@csstools/postcss-trigonometric-functions': 4.0.9(postcss@8.5.10) - '@csstools/postcss-unset-value': 4.0.0(postcss@8.5.10) - autoprefixer: 10.4.22(postcss@8.5.10) + postcss-preset-env@10.4.0(postcss@8.5.12): + dependencies: + '@csstools/postcss-alpha-function': 1.0.1(postcss@8.5.12) + '@csstools/postcss-cascade-layers': 5.0.2(postcss@8.5.12) + '@csstools/postcss-color-function': 4.0.12(postcss@8.5.12) + '@csstools/postcss-color-function-display-p3-linear': 1.0.1(postcss@8.5.12) + '@csstools/postcss-color-mix-function': 3.0.12(postcss@8.5.12) + '@csstools/postcss-color-mix-variadic-function-arguments': 1.0.2(postcss@8.5.12) + '@csstools/postcss-content-alt-text': 2.0.8(postcss@8.5.12) + '@csstools/postcss-contrast-color-function': 2.0.12(postcss@8.5.12) + '@csstools/postcss-exponential-functions': 2.0.9(postcss@8.5.12) + '@csstools/postcss-font-format-keywords': 4.0.0(postcss@8.5.12) + '@csstools/postcss-gamut-mapping': 2.0.11(postcss@8.5.12) + '@csstools/postcss-gradients-interpolation-method': 5.0.12(postcss@8.5.12) + '@csstools/postcss-hwb-function': 4.0.12(postcss@8.5.12) + '@csstools/postcss-ic-unit': 4.0.4(postcss@8.5.12) + '@csstools/postcss-initial': 2.0.1(postcss@8.5.12) + '@csstools/postcss-is-pseudo-class': 5.0.3(postcss@8.5.12) + '@csstools/postcss-light-dark-function': 2.0.11(postcss@8.5.12) + '@csstools/postcss-logical-float-and-clear': 3.0.0(postcss@8.5.12) + '@csstools/postcss-logical-overflow': 2.0.0(postcss@8.5.12) + '@csstools/postcss-logical-overscroll-behavior': 2.0.0(postcss@8.5.12) + '@csstools/postcss-logical-resize': 3.0.0(postcss@8.5.12) + '@csstools/postcss-logical-viewport-units': 3.0.4(postcss@8.5.12) + '@csstools/postcss-media-minmax': 2.0.9(postcss@8.5.12) + '@csstools/postcss-media-queries-aspect-ratio-number-values': 3.0.5(postcss@8.5.12) + '@csstools/postcss-nested-calc': 4.0.0(postcss@8.5.12) + '@csstools/postcss-normalize-display-values': 4.0.0(postcss@8.5.12) + '@csstools/postcss-oklab-function': 4.0.12(postcss@8.5.12) + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.12) + '@csstools/postcss-random-function': 2.0.1(postcss@8.5.12) + '@csstools/postcss-relative-color-syntax': 3.0.12(postcss@8.5.12) + '@csstools/postcss-scope-pseudo-class': 4.0.1(postcss@8.5.12) + '@csstools/postcss-sign-functions': 1.1.4(postcss@8.5.12) + '@csstools/postcss-stepped-value-functions': 4.0.9(postcss@8.5.12) + '@csstools/postcss-text-decoration-shorthand': 4.0.3(postcss@8.5.12) + '@csstools/postcss-trigonometric-functions': 4.0.9(postcss@8.5.12) + '@csstools/postcss-unset-value': 4.0.0(postcss@8.5.12) + autoprefixer: 10.4.22(postcss@8.5.12) browserslist: 4.28.1 - css-blank-pseudo: 7.0.1(postcss@8.5.10) - css-has-pseudo: 7.0.3(postcss@8.5.10) - css-prefers-color-scheme: 10.0.0(postcss@8.5.10) + css-blank-pseudo: 7.0.1(postcss@8.5.12) + css-has-pseudo: 7.0.3(postcss@8.5.12) + css-prefers-color-scheme: 10.0.0(postcss@8.5.12) cssdb: 8.4.3 - postcss: 8.5.10 - postcss-attribute-case-insensitive: 7.0.1(postcss@8.5.10) - postcss-clamp: 4.1.0(postcss@8.5.10) - postcss-color-functional-notation: 7.0.12(postcss@8.5.10) - postcss-color-hex-alpha: 10.0.0(postcss@8.5.10) - postcss-color-rebeccapurple: 10.0.0(postcss@8.5.10) - postcss-custom-media: 11.0.6(postcss@8.5.10) - postcss-custom-properties: 14.0.6(postcss@8.5.10) - postcss-custom-selectors: 8.0.5(postcss@8.5.10) - postcss-dir-pseudo-class: 9.0.1(postcss@8.5.10) - postcss-double-position-gradients: 6.0.4(postcss@8.5.10) - postcss-focus-visible: 10.0.1(postcss@8.5.10) - postcss-focus-within: 9.0.1(postcss@8.5.10) - postcss-font-variant: 5.0.0(postcss@8.5.10) - postcss-gap-properties: 6.0.0(postcss@8.5.10) - postcss-image-set-function: 7.0.0(postcss@8.5.10) - postcss-lab-function: 7.0.12(postcss@8.5.10) - postcss-logical: 8.1.0(postcss@8.5.10) - postcss-nesting: 13.0.2(postcss@8.5.10) - postcss-opacity-percentage: 3.0.0(postcss@8.5.10) - postcss-overflow-shorthand: 6.0.0(postcss@8.5.10) - postcss-page-break: 3.0.4(postcss@8.5.10) - postcss-place: 10.0.0(postcss@8.5.10) - postcss-pseudo-class-any-link: 10.0.1(postcss@8.5.10) - postcss-replace-overflow-wrap: 4.0.0(postcss@8.5.10) - postcss-selector-not: 8.0.1(postcss@8.5.10) - - postcss-pseudo-class-any-link@10.0.1(postcss@8.5.10): - dependencies: - postcss: 8.5.10 + postcss: 8.5.12 + postcss-attribute-case-insensitive: 7.0.1(postcss@8.5.12) + postcss-clamp: 4.1.0(postcss@8.5.12) + postcss-color-functional-notation: 7.0.12(postcss@8.5.12) + postcss-color-hex-alpha: 10.0.0(postcss@8.5.12) + postcss-color-rebeccapurple: 10.0.0(postcss@8.5.12) + postcss-custom-media: 11.0.6(postcss@8.5.12) + postcss-custom-properties: 14.0.6(postcss@8.5.12) + postcss-custom-selectors: 8.0.5(postcss@8.5.12) + postcss-dir-pseudo-class: 9.0.1(postcss@8.5.12) + postcss-double-position-gradients: 6.0.4(postcss@8.5.12) + postcss-focus-visible: 10.0.1(postcss@8.5.12) + postcss-focus-within: 9.0.1(postcss@8.5.12) + postcss-font-variant: 5.0.0(postcss@8.5.12) + postcss-gap-properties: 6.0.0(postcss@8.5.12) + postcss-image-set-function: 7.0.0(postcss@8.5.12) + postcss-lab-function: 7.0.12(postcss@8.5.12) + postcss-logical: 8.1.0(postcss@8.5.12) + postcss-nesting: 13.0.2(postcss@8.5.12) + postcss-opacity-percentage: 3.0.0(postcss@8.5.12) + postcss-overflow-shorthand: 6.0.0(postcss@8.5.12) + postcss-page-break: 3.0.4(postcss@8.5.12) + postcss-place: 10.0.0(postcss@8.5.12) + postcss-pseudo-class-any-link: 10.0.1(postcss@8.5.12) + postcss-replace-overflow-wrap: 4.0.0(postcss@8.5.12) + postcss-selector-not: 8.0.1(postcss@8.5.12) + + postcss-pseudo-class-any-link@10.0.1(postcss@8.5.12): + dependencies: + postcss: 8.5.12 postcss-selector-parser: 7.1.1 - postcss-reduce-idents@6.0.3(postcss@8.5.10): + postcss-reduce-idents@6.0.3(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-reduce-initial@6.1.0(postcss@8.5.10): + postcss-reduce-initial@6.1.0(postcss@8.5.12): dependencies: browserslist: 4.28.1 caniuse-api: 3.0.0 - postcss: 8.5.10 + postcss: 8.5.12 - postcss-reduce-transforms@6.0.2(postcss@8.5.10): + postcss-reduce-transforms@6.0.2(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - postcss-replace-overflow-wrap@4.0.0(postcss@8.5.10): + postcss-replace-overflow-wrap@4.0.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - postcss-selector-not@8.0.1(postcss@8.5.10): + postcss-selector-not@8.0.1(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 7.1.1 postcss-selector-parser@6.1.2: @@ -25481,29 +25598,29 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-sort-media-queries@5.2.0(postcss@8.5.10): + postcss-sort-media-queries@5.2.0(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 sort-css-media-queries: 2.2.0 - postcss-svgo@6.0.3(postcss@8.5.10): + postcss-svgo@6.0.3(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - svgo: 3.3.3 + svgo: 3.3.4 - postcss-unique-selectors@6.0.4(postcss@8.5.10): + postcss-unique-selectors@6.0.4(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 6.1.2 postcss-value-parser@4.2.0: {} - postcss-zindex@6.0.2(postcss@8.5.10): + postcss-zindex@6.0.2(postcss@8.5.12): dependencies: - postcss: 8.5.10 + postcss: 8.5.12 - postcss@8.5.10: + postcss@8.5.12: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -25647,7 +25764,7 @@ snapshots: dependencies: bytes: 3.1.2 http-errors: 2.0.1 - iconv-lite: 0.7.0 + iconv-lite: 0.7.3 unpipe: 1.0.0 rc-resize-observer@1.4.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0): @@ -25680,8 +25797,8 @@ snapshots: react-docgen@8.0.2: dependencies: '@babel/core': 7.29.6(supports-color@8.1.1) - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.29.7(supports-color@8.1.1) + '@babel/types': 7.29.7 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.28.0 '@types/doctrine': 0.0.9 @@ -26042,6 +26159,13 @@ snapshots: transitivePeerDependencies: - supports-color + require-in-the-middle@8.0.1(supports-color@8.1.1): + dependencies: + debug: 4.4.3(supports-color@8.1.1) + module-details-from-path: 1.0.4 + transitivePeerDependencies: + - supports-color + require-like@0.1.2: {} requires-port@1.0.0: {} @@ -26167,7 +26291,7 @@ snapshots: dependencies: escalade: 3.2.0 picocolors: 1.1.1 - postcss: 8.5.10 + postcss: 8.5.12 strip-json-comments: 3.1.1 run-applescript@7.1.0: {} @@ -26258,7 +26382,7 @@ snapshots: semver-diff@4.0.0: dependencies: - semver: 7.7.4 + semver: 7.8.0 semver@5.7.2: {} @@ -26266,8 +26390,6 @@ snapshots: semver@7.7.2: {} - semver@7.7.3: {} - semver@7.7.4: {} semver@7.8.0: {} @@ -26512,7 +26634,7 @@ snapshots: dependencies: faye-websocket: 0.11.4 uuid: 8.3.2 - websocket-driver: 0.7.4 + websocket-driver: 0.7.5 sort-css-media-queries@2.2.0: {} @@ -26613,9 +26735,9 @@ snapshots: stoppable@1.1.0: {} - storybook-addon-apollo-client@9.0.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(react@19.2.0): + storybook-addon-apollo-client@9.0.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(react@19.2.0): dependencies: - '@apollo/client': 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@apollo/client': 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.21.1))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) graphql: 16.12.0 react: 19.2.0 @@ -26635,7 +26757,7 @@ snapshots: recast: 0.23.11 semver: 7.8.0 use-sync-external-store: 1.6.0(react@19.2.0) - ws: 8.21.0 + ws: 8.21.1 optionalDependencies: '@types/react': 19.2.7 transitivePeerDependencies: @@ -26773,10 +26895,10 @@ snapshots: dependencies: inline-style-parser: 0.2.7 - stylehacks@6.1.1(postcss@8.5.10): + stylehacks@6.1.1(postcss@8.5.12): dependencies: browserslist: 4.28.1 - postcss: 8.5.10 + postcss: 8.5.12 postcss-selector-parser: 6.1.2 stylis@4.3.6: {} @@ -26788,7 +26910,7 @@ snapshots: lines-and-columns: 1.2.4 mz: 2.7.0 pirates: 4.0.7 - tinyglobby: 0.2.15 + tinyglobby: 0.2.17 ts-interface-checker: 0.1.13 supports-color@5.5.0: @@ -26807,7 +26929,7 @@ snapshots: svg-parser@2.0.4: {} - svgo@3.3.3: + svgo@3.3.4: dependencies: commander: 7.2.0 css-select: 5.2.2 @@ -26855,11 +26977,11 @@ snapshots: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.10 - postcss-import: 15.1.0(postcss@8.5.10) - postcss-js: 4.1.0(postcss@8.5.10) - postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(yaml@2.8.3) - postcss-nested: 6.2.0(postcss@8.5.10) + postcss: 8.5.12 + postcss-import: 15.1.0(postcss@8.5.12) + postcss-js: 4.1.0(postcss@8.5.12) + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.12)(tsx@4.21.0)(yaml@2.8.3) + postcss-nested: 6.2.0(postcss@8.5.12) postcss-selector-parser: 6.1.2 resolve: 1.22.11 sucrase: 3.35.1 @@ -26915,13 +27037,13 @@ snapshots: dependencies: '@istanbuljs/schema': 0.1.3 glob: 10.5.0 - minimatch: 10.2.4 + minimatch: 10.2.5 test-exclude@8.0.0: dependencies: '@istanbuljs/schema': 0.1.3 glob: 13.0.6 - minimatch: 10.2.4 + minimatch: 10.2.5 text-decoder@1.2.3: dependencies: @@ -26974,11 +27096,6 @@ snapshots: tinyexec@1.0.4: {} - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.4) @@ -27292,7 +27409,7 @@ snapshots: is-yarn-global: 0.4.1 latest-version: 7.0.0 pupa: 3.3.0 - semver: 7.7.4 + semver: 7.8.0 semver-diff: 4.0.0 xdg-basedir: 5.1.0 @@ -27411,7 +27528,7 @@ snapshots: dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.10 + postcss: 8.5.12 rolldown: 1.0.3 tinyglobby: 0.2.17 optionalDependencies: @@ -27428,7 +27545,7 @@ snapshots: dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.10 + postcss: 8.5.12 rolldown: 1.0.3 tinyglobby: 0.2.17 optionalDependencies: @@ -27441,16 +27558,16 @@ snapshots: tsx: 4.21.0 yaml: 2.8.3 - vitest@4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)): + vitest@4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.19.15)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: - '@vitest/expect': 4.1.8 - '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) - '@vitest/pretty-format': 4.1.8 - '@vitest/runner': 4.1.8 - '@vitest/snapshot': 4.1.8 - '@vitest/spy': 4.1.8 - '@vitest/utils': 4.1.8 - es-module-lexer: 2.0.0 + '@vitest/expect': 4.1.10 + '@vitest/mocker': 4.1.10(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.10 + '@vitest/runner': 4.1.10 + '@vitest/snapshot': 4.1.10 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 + es-module-lexer: 2.3.1 expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 @@ -27466,23 +27583,23 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 22.19.15 - '@vitest/browser-playwright': 4.1.8(playwright@1.59.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8) - '@vitest/coverage-istanbul': 4.1.8(supports-color@8.1.1)(vitest@4.1.8) + '@vitest/browser-playwright': 4.1.10(playwright@1.59.0)(vite@8.0.16(@types/node@22.19.15)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10) + '@vitest/coverage-istanbul': 4.1.10(supports-color@8.1.1)(vitest@4.1.10) happy-dom: 20.10.1 jsdom: 26.1.0 transitivePeerDependencies: - msw - vitest@4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.8)(@vitest/coverage-istanbul@4.1.8)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)): + vitest@4.1.10(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-istanbul@4.1.10)(happy-dom@20.10.1)(jsdom@26.1.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: - '@vitest/expect': 4.1.8 - '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) - '@vitest/pretty-format': 4.1.8 - '@vitest/runner': 4.1.8 - '@vitest/snapshot': 4.1.8 - '@vitest/spy': 4.1.8 - '@vitest/utils': 4.1.8 - es-module-lexer: 2.0.0 + '@vitest/expect': 4.1.10 + '@vitest/mocker': 4.1.10(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.10 + '@vitest/runner': 4.1.10 + '@vitest/snapshot': 4.1.10 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 + es-module-lexer: 2.3.1 expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 @@ -27498,8 +27615,8 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 24.10.1 - '@vitest/browser-playwright': 4.1.8(playwright@1.59.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.8) - '@vitest/coverage-istanbul': 4.1.8(vitest@4.1.8) + '@vitest/browser-playwright': 4.1.10(playwright@1.59.0)(vite@8.0.16(@types/node@24.10.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.10) + '@vitest/coverage-istanbul': 4.1.10(vitest@4.1.10) happy-dom: 20.10.1 jsdom: 26.1.0 transitivePeerDependencies: @@ -27551,7 +27668,7 @@ snapshots: opener: 1.5.2 picocolors: 1.1.1 sirv: 2.0.4 - ws: 8.21.0 + ws: 8.21.1 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -27596,7 +27713,7 @@ snapshots: sockjs: 0.3.24 spdy: 4.0.2 webpack-dev-middleware: 7.4.5(webpack@5.105.4(esbuild@0.28.1)) - ws: 8.21.0 + ws: 8.21.1 optionalDependencies: webpack: 5.105.4(esbuild@0.28.1) transitivePeerDependencies: @@ -27633,7 +27750,7 @@ snapshots: browserslist: 4.28.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.20.0 - es-module-lexer: 2.0.0 + es-module-lexer: 2.3.1 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -27661,7 +27778,7 @@ snapshots: optionalDependencies: webpack: 5.105.4(esbuild@0.28.1) - websocket-driver@0.7.4: + websocket-driver@0.7.5: dependencies: http-parser-js: 0.5.10 safe-buffer: 5.2.1 @@ -27802,7 +27919,7 @@ snapshots: signal-exit: 3.0.7 typedarray-to-buffer: 3.1.5 - ws@8.21.0: {} + ws@8.21.1: {} wsl-utils@0.1.0: dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index d72187af9..61b6ad1ba 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -25,9 +25,9 @@ catalog: '@serenity-js/cucumber': 3.43.0 '@serenity-js/serenity-bdd': 3.43.0 '@types/node': ^22.19.5 - '@vitest/browser': 4.1.8 - '@vitest/browser-playwright': 4.1.8 - '@vitest/coverage-istanbul': 4.1.8 + '@vitest/browser': 4.1.10 + '@vitest/browser-playwright': 4.1.10 + '@vitest/coverage-istanbul': 4.1.10 antd: 6.3.5 archunit: ^2.1.63 esbuild: 0.28.1 @@ -52,7 +52,7 @@ catalog: typescript: 6.0.3 "@typescript/native-preview": 7.0.0-dev.20260428.1 vite: 8.0.16 - vitest: 4.1.8 + vitest: 4.1.10 vite-plugin-node-polyfills: ^0.28.0 auditConfig: @@ -75,10 +75,10 @@ allowBuilds: snyk: true overrides: - '@vitest/browser': 4.1.8 - '@vitest/browser-playwright': 4.1.8 + '@vitest/browser': 4.1.10 + '@vitest/browser-playwright': 4.1.10 happy-dom: 20.10.1 - axios: 1.16.0 + axios: 1.18.0 body-parser: 2.3.0 esbuild: 'catalog:' follow-redirects: ^1.16.0 @@ -93,7 +93,7 @@ overrides: 'serve-handler>minimatch': 3.1.5 'serialize-javascript@6.0.2': 7.0.5 'serialize-javascript@7.0.4': 7.0.5 - svgo: ^3.3.3 + svgo: ^3.3.4 'yaml@2.8.2': 2.8.3 'yauzl@3.2.0': 3.2.1 qs: 6.15.2 @@ -113,10 +113,10 @@ overrides: 'ws@8.20.0': 8.21.0 playwright-core: 1.59.0 playwright: 1.59.0 - postcss: 8.5.10 + postcss: 8.5.12 protobufjs: 7.6.5 ip-address: ^10.1.1 - fast-uri: ^4.0.1 + fast-uri: ^4.1.1 '@babel/plugin-transform-modules-systemjs': 7.29.4 '@babel/core': ^7.29.6 js-yaml: 4.3.0 @@ -124,7 +124,8 @@ overrides: 'shell-quote@<1.8.4': 1.8.4 '@opentelemetry/exporter-prometheus@0.57.2': 0.217.0 '@opentelemetry/core@2.7.1': 2.8.0 - ws: 8.21.0 + ws: 8.21.1 + websocket-driver: 0.7.5 shell-quote: 1.9.0 '@grpc/grpc-js': '>=1.14.4' form-data: ^4.0.6