diff --git a/apps/edr-passenger-api/package.json b/apps/edr-passenger-api/package.json index b3571871c..230a44529 100644 --- a/apps/edr-passenger-api/package.json +++ b/apps/edr-passenger-api/package.json @@ -46,7 +46,7 @@ "@prisma/client": "^6.19.3", "@sendgrid/mail": "^8.1.0", "@tria-plc/api-common": "file:../../local-packages/tria-plc-api-common-1.6.0.tgz", - "@tria-plc/iamapi-common": "file:../../local-packages/tria-plc-iamapi-common-1.0.0.tgz", + "@tria-plc/iamapi-common": "file:../../local-packages/tria-plc-iamapi-common-1.1.0.tgz", "@types/bcrypt": "^6.0.0", "amqp-connection-manager": "^5.0.0", "amqplib": "^2.0.1", diff --git a/apps/edr-passenger-api/src/common/passenger-permission.util.spec.ts b/apps/edr-passenger-api/src/common/passenger-permission.util.spec.ts new file mode 100644 index 000000000..7d15fba00 --- /dev/null +++ b/apps/edr-passenger-api/src/common/passenger-permission.util.spec.ts @@ -0,0 +1,280 @@ +import { ForbiddenException } from '@nestjs/common'; +import { + assertPassengerPermission, + collectPermissionKeys, + hasPassengerPermission, + hasPassengerPermissionStrict, + isOrganizationAdmin, + isSuperAdmin, +} from './passenger-permission.util'; + +const TICKETS_MANAGE = 'edr_passenger_app:tickets:manage'; +const TICKETS_VIEW = 'edr_passenger_app:tickets:view'; +const BOOKINGS_VIEW = 'edr_passenger_app:bookings:view'; +const FLEET_MANAGE = 'edr_passenger_app:fleet:manage'; + +/** IAM shape: position types nest the key one level deeper, under `.permission`. */ +const positionType = (keys: string[]) => ({ + positionTypePermissions: keys.map((key) => ({ permission: { key } })), +}); + +/** Mirrors the ticket-officer position IAM returns: own grant + two position types. */ +const ticketOfficerPosition = () => ({ + id: 'pos-ticket-officer', + permissions: [{ key: BOOKINGS_VIEW }], + positionType: positionType([TICKETS_VIEW, TICKETS_MANAGE]), + positionTypes: [ + positionType(['can:view:expectation']), + positionType([TICKETS_VIEW, TICKETS_MANAGE]), + ], +}); + +const hrPosition = () => ({ + id: 'pos-hr', + permissions: [{ key: 'hr_app:employees:view' }], + positionType: positionType(['hr_app:leave:approve']), + positionTypes: [positionType(['hr_app:leave:approve'])], +}); + +/** `/v1/auth/me` — `employee` is an array of employees, each with `positions[]`. */ +const meShape = (positions: any[]) => ({ + roles: [], + permissions: [], + employee: [{ id: 'emp-1', positions }], +}); + +/** + * `request.user` — `JwtGuard.parseToken` spreads the employee, then overwrites + * `position` with the one it selected and adds `delegatedPositions[]`. The full + * `positions[]` survives the spread. + */ +const requestShape = (positions: any[], selectedIndex = 0) => ({ + roles: [], + permissions: [], + employee: { + id: 'emp-1', + positions, + position: positions[selectedIndex], + delegatedPositions: positions.filter((p: any) => p.isDelegate), + }, +}); + +describe('collectPermissionKeys', () => { + it('returns nothing for a missing user', () => { + expect(collectPermissionKeys(null)).toEqual([]); + expect(collectPermissionKeys(undefined)).toEqual([]); + expect(collectPermissionKeys({})).toEqual([]); + }); + + it('collects role permissions when there is no employee record', () => { + expect(collectPermissionKeys({ permissions: [{ key: TICKETS_VIEW }] })).toEqual([TICKETS_VIEW]); + expect(collectPermissionKeys({ permissions: [{ key: TICKETS_VIEW }], employee: null })).toEqual([ + TICKETS_VIEW, + ]); + }); + + describe('backward compatibility — positions with no position types', () => { + it('still reads a position own permissions[] in the /v1/auth/me shape', () => { + const user = meShape([{ id: 'p1', permissions: [{ key: BOOKINGS_VIEW }] }]); + expect(collectPermissionKeys(user)).toEqual([BOOKINGS_VIEW]); + }); + + it('still reads a position own permissions[] in the request.user shape', () => { + const user = requestShape([{ id: 'p1', permissions: [{ key: BOOKINGS_VIEW }] }]); + expect(collectPermissionKeys(user)).toEqual([BOOKINGS_VIEW]); + }); + + it('merges role permissions with position permissions', () => { + const user = { + permissions: [{ key: 'role:key' }], + employee: [{ positions: [{ permissions: [{ key: BOOKINGS_VIEW }] }] }], + }; + expect(collectPermissionKeys(user).sort()).toEqual([BOOKINGS_VIEW, 'role:key'].sort()); + }); + }); + + describe('position types', () => { + it('collects from the legacy singular positionType', () => { + const user = meShape([{ permissions: [], positionType: positionType([TICKETS_MANAGE]) }]); + expect(collectPermissionKeys(user)).toEqual([TICKETS_MANAGE]); + }); + + it('collects from the new positionTypes[] array', () => { + const user = meShape([{ permissions: [], positionTypes: [positionType([TICKETS_MANAGE])] }]); + expect(collectPermissionKeys(user)).toEqual([TICKETS_MANAGE]); + }); + + it('collects from every entry of positionTypes[], not just the first', () => { + const user = meShape([ + { + permissions: [], + positionTypes: [positionType(['a']), positionType(['b']), positionType(['c'])], + }, + ]); + expect(collectPermissionKeys(user).sort()).toEqual(['a', 'b', 'c']); + }); + + it('unions permissions[], positionType and positionTypes[] without duplicates', () => { + // ticket-officer appears as BOTH the singular positionType and inside positionTypes[] + const keys = collectPermissionKeys(meShape([ticketOfficerPosition()])); + expect(keys.sort()).toEqual( + [BOOKINGS_VIEW, TICKETS_VIEW, TICKETS_MANAGE, 'can:view:expectation'].sort(), + ); + expect(keys).toHaveLength(new Set(keys).size); + }); + + it('works identically in the request.user shape', () => { + expect(collectPermissionKeys(requestShape([ticketOfficerPosition()])).sort()).toEqual( + collectPermissionKeys(meShape([ticketOfficerPosition()])).sort(), + ); + }); + }); + + describe('all positions count, not only the selected one', () => { + it('grants a permission held by a position that is not positions[0]', () => { + // parseToken selected positions[0] (HR) because no x-current-position-id was sent + const user = requestShape([hrPosition(), ticketOfficerPosition()], 0); + expect(collectPermissionKeys(user)).toContain(TICKETS_MANAGE); + }); + + it('matches what the backoffice computes from the same payload', () => { + const positions = [hrPosition(), ticketOfficerPosition()]; + expect(collectPermissionKeys(requestShape(positions, 0)).sort()).toEqual( + collectPermissionKeys(meShape(positions)).sort(), + ); + }); + + it('spans multiple employee records', () => { + const user = { + employee: [{ positions: [hrPosition()] }, { positions: [ticketOfficerPosition()] }], + }; + expect(collectPermissionKeys(user)).toContain(TICKETS_MANAGE); + expect(collectPermissionKeys(user)).toContain('hr_app:leave:approve'); + }); + + it('includes delegated positions', () => { + const delegated = { ...ticketOfficerPosition(), isDelegate: true }; + const user = { + employee: { positions: undefined, position: hrPosition(), delegatedPositions: [delegated] }, + }; + expect(collectPermissionKeys(user)).toContain(TICKETS_MANAGE); + }); + + it('does not invent permissions nobody was granted', () => { + const user = requestShape([hrPosition(), ticketOfficerPosition()]); + expect(collectPermissionKeys(user)).not.toContain(FLEET_MANAGE); + }); + }); + + describe('malformed payloads', () => { + it('survives nulls, missing keys and non-array fields', () => { + const user: any = { + permissions: [{}, { key: 'kept' }], + employee: { + // parseToken passes `positions` through untouched when it is not an array + positions: { id: 'not-an-array' }, + position: { + permissions: null, + positionType: null, + positionTypes: [null, { positionTypePermissions: null }, positionType([TICKETS_VIEW])], + }, + delegatedPositions: null, + }, + }; + expect(collectPermissionKeys(user).sort()).toEqual(['kept', TICKETS_VIEW].sort()); + }); + + it('ignores positionTypePermissions entries with no permission object', () => { + const user: any = { + employee: [ + { + positions: [ + { + positionTypes: [ + { + positionTypePermissions: [ + {}, + { permission: null }, + { permission: { key: 'ok' } }, + ], + }, + ], + }, + ], + }, + ], + }; + expect(collectPermissionKeys(user)).toEqual(['ok']); + }); + }); +}); + +describe('role helpers', () => { + it('detects super admin and org admin', () => { + expect(isSuperAdmin({ roles: [{ key: 'super_admin' }] })).toBe(true); + expect(isOrganizationAdmin({ roles: [{ key: 'organization_admin' }] })).toBe(true); + expect(isSuperAdmin({ roles: [{ key: 'ticket_officer' }] })).toBe(false); + expect(isOrganizationAdmin({})).toBe(false); + }); +}); + +describe('hasPassengerPermission', () => { + it('is true for a permission granted only through a position type', () => { + expect(hasPassengerPermission(requestShape([ticketOfficerPosition()]), TICKETS_MANAGE)).toBe( + true, + ); + }); + + it('is true when the granting position is not the selected one', () => { + const user = requestShape([hrPosition(), ticketOfficerPosition()], 0); + expect(hasPassengerPermission(user, TICKETS_MANAGE)).toBe(true); + }); + + it('is false for a permission nobody granted', () => { + expect(hasPassengerPermission(requestShape([ticketOfficerPosition()]), FLEET_MANAGE)).toBe( + false, + ); + }); + + it('is false without a user', () => { + expect(hasPassengerPermission(null, TICKETS_MANAGE)).toBe(false); + }); + + it('lets super admins and org admins bypass', () => { + expect(hasPassengerPermission({ roles: [{ key: 'super_admin' }] }, FLEET_MANAGE)).toBe(true); + expect(hasPassengerPermission({ roles: [{ key: 'organization_admin' }] }, FLEET_MANAGE)).toBe( + true, + ); + }); +}); + +describe('hasPassengerPermissionStrict', () => { + it('does not let super admins bypass', () => { + expect(hasPassengerPermissionStrict({ roles: [{ key: 'super_admin' }] }, FLEET_MANAGE)).toBe( + false, + ); + }); + + it('honours a position-type grant', () => { + expect(hasPassengerPermissionStrict(requestShape([ticketOfficerPosition()]), TICKETS_MANAGE)).toBe( + true, + ); + }); +}); + +describe('assertPassengerPermission', () => { + it('passes silently when granted through a position type', () => { + expect(() => + assertPassengerPermission(requestShape([ticketOfficerPosition()]), TICKETS_MANAGE), + ).not.toThrow(); + }); + + it('throws ForbiddenException naming the missing key', () => { + expect(() => assertPassengerPermission(requestShape([hrPosition()]), TICKETS_MANAGE)).toThrow( + ForbiddenException, + ); + expect(() => assertPassengerPermission(requestShape([hrPosition()]), TICKETS_MANAGE)).toThrow( + TICKETS_MANAGE, + ); + }); +}); diff --git a/apps/edr-passenger-api/src/common/passenger-permission.util.ts b/apps/edr-passenger-api/src/common/passenger-permission.util.ts index d915ef86e..cc94b0e0c 100644 --- a/apps/edr-passenger-api/src/common/passenger-permission.util.ts +++ b/apps/edr-passenger-api/src/common/passenger-permission.util.ts @@ -4,13 +4,34 @@ const SUPER_ADMIN_ROLE = 'super_admin'; const ORGANIZATION_ADMIN_ROLE = 'organization_admin'; type PermissionLike = { key?: string }; + +/** + * A position type carries its own grants. IAM ships them as + * `positionTypePermissions[].permission.key` — note the extra `permission` + * wrapper, unlike the flat `permissions[]` on a position. + */ +type PositionTypeLike = { + positionTypePermissions?: ({ permission?: PermissionLike | null } | null)[] | null; +}; + +type PositionLike = { + permissions?: PermissionLike[]; + /** Legacy single position type. */ + positionType?: PositionTypeLike | null; + /** Newer array — a position can now carry several position types. */ + positionTypes?: (PositionTypeLike | null)[] | null; +}; + +type EmployeeLike = { + position?: PositionLike; + positions?: PositionLike[]; + delegatedPositions?: PositionLike[]; +}; + type MeLikeUser = { roles?: { key?: string }[]; permissions?: PermissionLike[]; - employee?: - | { position?: { permissions?: PermissionLike[] }; delegatedPositions?: { permissions?: PermissionLike[] }[] } - | { positions?: { permissions?: PermissionLike[] }[] }[] - | null; + employee?: EmployeeLike | EmployeeLike[] | null; }; export function isSuperAdmin(user: MeLikeUser | null | undefined): boolean { @@ -21,6 +42,42 @@ export function isOrganizationAdmin(user: MeLikeUser | null | undefined): boolea return user?.roles?.some((r) => r.key === ORGANIZATION_ADMIN_ROLE) ?? false; } +/** + * Add every permission key a single position grants. + * + * A position's own `permissions[]` used to be the whole story. IAM now also + * hangs grants off *position types* — the legacy singular `positionType` plus + * the newer `positionTypes[]` array — so we union all three rather than trust + * IAM to have merged them back into `permissions[]`. + */ +function addPositionPermissionKeys( + position: PositionLike | null | undefined, + keys: Set, +): void { + if (!position) return; + + for (const p of position.permissions ?? []) { + if (p?.key) keys.add(p.key); + } + + const positionTypes: (PositionTypeLike | null | undefined)[] = [ + position.positionType, + ...(position.positionTypes ?? []), + ]; + + for (const positionType of positionTypes) { + for (const ptp of positionType?.positionTypePermissions ?? []) { + const key = ptp?.permission?.key; + if (key) keys.add(key); + } + } +} + +/** `parseToken` passes `positions` through untouched, so it is not always an array. */ +function asArray(value: T[] | null | undefined): T[] { + return Array.isArray(value) ? value : []; +} + export function collectPermissionKeys(user: MeLikeUser | null | undefined): string[] { if (!user) return []; @@ -33,23 +90,25 @@ export function collectPermissionKeys(user: MeLikeUser | null | undefined): stri const employee = user.employee; if (!employee) return [...keys]; - if (Array.isArray(employee)) { - for (const emp of employee) { - for (const pos of emp.positions ?? []) { - for (const p of pos.permissions ?? []) { - if (p.key) keys.add(p.key); - } - } - } - return [...keys]; - } + // `/v1/auth/me` hands back `employee` as an array of employees, each with + // `positions[]`. `JwtGuard.parseToken` collapses it to a single employee with + // the active `position` plus `delegatedPositions[]` — but it spreads the + // employee, so the full `positions[]` survives on `request.user` too. Both + // shapes reach here. + const employees = Array.isArray(employee) ? employee : [employee]; - for (const p of employee.position?.permissions ?? []) { - if (p.key) keys.add(p.key); - } - for (const delegated of employee.delegatedPositions ?? []) { - for (const p of delegated.permissions ?? []) { - if (p.key) keys.add(p.key); + for (const emp of employees) { + // Every position the person holds counts, not just the one + // `parseToken` selected. Without a `x-current-position-id` header it picks + // `positions[0]`, so a second-listed passenger position would 403 here while + // the backoffice — which unions all positions at login — renders the action + // as available. Union them here so the two agree. + addPositionPermissionKeys(emp.position, keys); + for (const pos of asArray(emp.positions)) { + addPositionPermissionKeys(pos, keys); + } + for (const delegated of asArray(emp.delegatedPositions)) { + addPositionPermissionKeys(delegated, keys); } } diff --git a/apps/edr-passenger-web/backoffice/src/lib/auth-store.ts b/apps/edr-passenger-web/backoffice/src/lib/auth-store.ts index aadd86057..8a4766f82 100644 --- a/apps/edr-passenger-web/backoffice/src/lib/auth-store.ts +++ b/apps/edr-passenger-web/backoffice/src/lib/auth-store.ts @@ -6,6 +6,33 @@ import axios from 'axios'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; +/** + * Every permission key a single IAM position grants. + * + * A position's own `permissions[]` used to be the whole story. IAM now also + * hangs grants off *position types* — the legacy singular `positionType` plus + * the newer `positionTypes[]` array, whose entries expose + * `positionTypePermissions[].permission.key` (note the extra `permission` + * wrapper). Union all three rather than trust IAM to have merged them back into + * `permissions[]`. Mirrors collectPermissionKeys() on the API. + */ +export function positionPermissionKeys(pos: any): string[] { + const keys: string[] = (pos?.permissions ?? []) + .map((p: any) => p?.key) + .filter(Boolean) + .map(String); + + const positionTypes: any[] = [pos?.positionType, ...(pos?.positionTypes ?? [])]; + for (const pt of positionTypes) { + for (const ptp of pt?.positionTypePermissions ?? []) { + const key = ptp?.permission?.key; + if (key) keys.push(String(key)); + } + } + + return keys; +} + function mapIamRole(roles: { key?: string }[]): 'ADMIN' | 'AGENT' | 'SUPERVISOR' { const keys = roles.map((r) => r.key ?? ''); if (keys.some((k) => k.includes('admin') || k === 'super_admin' || k === 'organization_admin')) return 'ADMIN'; @@ -70,12 +97,11 @@ export const useAuthStore = create((set, get) => ({ // Role permissions — flat array in data.permissions const rolePerms = (iamUser.permissions ?? []).map((p: any) => String(p.key)); - // Position permissions — employee[] is an array here; positions[].permissions[] merged by IAM + // Position permissions — employee[] is an array here; each position contributes + // its own permissions[] plus everything its position type(s) grant. const employeeArr: any[] = Array.isArray(iamUser.employee) ? iamUser.employee : []; const positionPerms = employeeArr.flatMap((emp: any) => - (emp.positions ?? []).flatMap((pos: any) => - (pos.permissions ?? []).map((p: any) => String(p.key)) - ) + (emp.positions ?? []).flatMap((pos: any) => positionPermissionKeys(pos)) ); const permissions = Array.from(new Set([...rolePerms, ...positionPerms])); diff --git a/local-packages/tria-plc-iamapi-common-1.1.0.tgz b/local-packages/tria-plc-iamapi-common-1.1.0.tgz new file mode 100644 index 000000000..8bbb76bf9 Binary files /dev/null and b/local-packages/tria-plc-iamapi-common-1.1.0.tgz differ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8e8768819..25037a2ae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -604,7 +604,7 @@ importers: version: 5.101.0(react@19.2.6) '@tria-plc/iamui': specifier: file:../../../local-packages/tria-plc-iamui-0.1.1.tgz - version: file:local-packages/tria-plc-iamui-0.1.1.tgz(0ce39b7e349029277dcd938d06eeb0f7) + version: file:local-packages/tria-plc-iamui-0.1.1.tgz(a5d0bdee55164ae56064fb273b530e00) '@vis.gl/react-google-maps': specifier: ^1.8.3 version: 1.8.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -836,8 +836,8 @@ importers: specifier: file:../../local-packages/tria-plc-api-common-1.6.0.tgz version: file:local-packages/tria-plc-api-common-1.6.0.tgz(2b4e99ab22f78c34e7861d649f4ff29b) '@tria-plc/iamapi-common': - specifier: file:../../local-packages/tria-plc-iamapi-common-1.0.0.tgz - version: file:local-packages/tria-plc-iamapi-common-1.0.0.tgz(cc085a020c559b355f168432c579a024) + specifier: file:../../local-packages/tria-plc-iamapi-common-1.1.0.tgz + version: file:local-packages/tria-plc-iamapi-common-1.1.0.tgz(cc085a020c559b355f168432c579a024) '@types/bcrypt': specifier: ^6.0.0 version: 6.0.0 @@ -5051,6 +5051,28 @@ packages: rxjs: ^7.8.0 typeorm: ^0.3.0 + '@tria-plc/iamapi-common@file:local-packages/tria-plc-iamapi-common-1.1.0.tgz': + resolution: {integrity: sha512-MWsfKmd+6+LxMx6fpJR9+c9oFtxiaNwR3KW2ptRVGinnmHofmqAsC3nURhRqTyWQeUbdNrvRdoiZtRx/0936Pw==, tarball: file:local-packages/tria-plc-iamapi-common-1.1.0.tgz} + version: 1.1.0 + engines: {node: '>=20'} + peerDependencies: + '@nestjs/axios': ^4.0.0 + '@nestjs/common': ^11.0.0 + '@nestjs/core': ^11.0.0 + '@nestjs/jwt': ^11.0.0 + '@nestjs/microservices': ^11.0.0 + '@nestjs/passport': ^11.0.0 + '@nestjs/swagger': ^11.0.0 + '@nestjs/throttler': ^6.0.0 + '@nestjs/typeorm': ^11.0.0 + '@tria-plc/api-common': '*' + axios: ^1.9.0 + class-transformer: ^0.5.1 + class-validator: ^0.14.1 + reflect-metadata: ^0.2.0 + rxjs: ^7.8.0 + typeorm: ^0.3.0 + '@tria-plc/iamui@file:local-packages/tria-plc-iamui-0.1.1.tgz': resolution: {integrity: sha512-FTihoH0lIqKV/0s+FTJZokQw8xX3XztXIqT8eEYEZgDM2xyzVSCHY8pHCUxw0MQtiR8R97zxZJ/o192eWt+E/g==, tarball: file:local-packages/tria-plc-iamui-0.1.1.tgz} version: 0.1.1 @@ -13059,11 +13081,11 @@ snapshots: '@babel/helpers': 7.29.7 '@babel/parser': 7.29.7 '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@5.5.0) + '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -13098,7 +13120,7 @@ snapshots: '@babel/helper-optimise-call-expression': 7.29.7 '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@5.5.0) + '@babel/traverse': 7.29.7 semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -13107,7 +13129,14 @@ snapshots: '@babel/helper-member-expression-to-functions@7.29.7': dependencies: - '@babel/traverse': 7.29.7(supports-color@5.5.0) + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color @@ -13122,9 +13151,9 @@ snapshots: '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': dependencies: '@babel/core': 7.29.7 - '@babel/helper-module-imports': 7.29.7(supports-color@5.5.0) + '@babel/helper-module-imports': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@5.5.0) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color @@ -13139,13 +13168,13 @@ snapshots: '@babel/core': 7.29.7 '@babel/helper-member-expression-to-functions': 7.29.7 '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@5.5.0) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.29.7': dependencies: - '@babel/traverse': 7.29.7(supports-color@5.5.0) + '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color @@ -13298,6 +13327,18 @@ snapshots: '@babel/parser': 7.29.7 '@babel/types': 7.29.7 + '@babel/traverse@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + debug: 4.4.3(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + '@babel/traverse@7.29.7(supports-color@5.5.0)': dependencies: '@babel/code-frame': 7.29.7 @@ -13782,7 +13823,7 @@ snapshots: '@emotion/babel-plugin@11.13.5': dependencies: - '@babel/helper-module-imports': 7.29.7(supports-color@5.5.0) + '@babel/helper-module-imports': 7.29.7 '@babel/runtime': 7.29.7 '@emotion/hash': 0.9.2 '@emotion/memoize': 0.9.0 @@ -13948,7 +13989,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.15.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -14108,7 +14149,7 @@ snapshots: '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -15707,7 +15748,7 @@ snapshots: '@puppeteer/browsers@2.13.2': dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) extract-zip: 2.0.1 progress: 2.0.3 proxy-agent: 6.5.0 @@ -17781,7 +17822,7 @@ snapshots: '@tokenizer/inflate@0.4.1': dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) token-types: 6.1.2 transitivePeerDependencies: - supports-color @@ -17876,7 +17917,7 @@ snapshots: - debug - supports-color - '@tria-plc/iamapi-common@file:local-packages/tria-plc-iamapi-common-1.0.0.tgz(cc085a020c559b355f168432c579a024)': + '@tria-plc/iamapi-common@file:local-packages/tria-plc-iamapi-common-1.0.0.tgz(d0be280d95adfc1b38e59bdc80c5dec5)': dependencies: '@nestjs/axios': 4.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.17.0)(rxjs@7.8.2) '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -17884,10 +17925,10 @@ snapshots: '@nestjs/jwt': 11.0.2(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)) '@nestjs/microservices': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(@nestjs/websockets@11.1.27)(amqp-connection-manager@5.0.0(amqplib@2.0.1))(amqplib@2.0.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/passport': 10.0.3(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) - '@nestjs/swagger': 7.4.2(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + '@nestjs/swagger': 11.4.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2) '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) - '@tria-plc/api-common': file:local-packages/tria-plc-api-common-1.6.0.tgz(2b4e99ab22f78c34e7861d649f4ff29b) + '@tria-plc/api-common': file:local-packages/tria-plc-api-common-1.6.0.tgz(ae9a56cc1c6d93629dd85f7605ccd5b6) argon2: 0.43.1 axios: 1.17.0 class-transformer: 0.5.1 @@ -17910,7 +17951,7 @@ snapshots: - '@faker-js/faker' - supports-color - '@tria-plc/iamapi-common@file:local-packages/tria-plc-iamapi-common-1.0.0.tgz(d0be280d95adfc1b38e59bdc80c5dec5)': + '@tria-plc/iamapi-common@file:local-packages/tria-plc-iamapi-common-1.1.0.tgz(cc085a020c559b355f168432c579a024)': dependencies: '@nestjs/axios': 4.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.17.0)(rxjs@7.8.2) '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -17918,10 +17959,10 @@ snapshots: '@nestjs/jwt': 11.0.2(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)) '@nestjs/microservices': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(@nestjs/websockets@11.1.27)(amqp-connection-manager@5.0.0(amqplib@2.0.1))(amqplib@2.0.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/passport': 10.0.3(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) - '@nestjs/swagger': 11.4.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + '@nestjs/swagger': 7.4.2(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2) '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.42)(typescript@5.9.3))) - '@tria-plc/api-common': file:local-packages/tria-plc-api-common-1.6.0.tgz(ae9a56cc1c6d93629dd85f7605ccd5b6) + '@tria-plc/api-common': file:local-packages/tria-plc-api-common-1.6.0.tgz(2b4e99ab22f78c34e7861d649f4ff29b) argon2: 0.43.1 axios: 1.17.0 class-transformer: 0.5.1 @@ -18068,6 +18109,130 @@ snapshots: - utf-8-validate - vite + '@tria-plc/iamui@file:local-packages/tria-plc-iamui-0.1.1.tgz(a5d0bdee55164ae56064fb273b530e00)': + dependencies: + '@emotion/react': 11.14.0(@types/react@18.3.31)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.31)(react@19.2.6))(@types/react@18.3.31)(react@19.2.6) + '@hookform/resolvers': 5.4.0(react-hook-form@7.77.0(react@19.2.6)) + '@lottiefiles/react-lottie-player': 3.6.0(react@19.2.6) + '@mantine/charts': 7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(recharts@3.8.1(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6)(redux@5.0.1)) + '@mantine/core': 7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/dates': 7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(dayjs@1.11.21)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/hooks': 7.17.8(react@19.2.6) + '@mantine/notifications': 7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-accordion': 1.2.13(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-alert-dialog': 1.1.16(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-avatar': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-checkbox': 1.3.4(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-collapsible': 1.1.13(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-context-menu': 2.3.0(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-dialog': 1.1.16(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-dropdown-menu': 2.1.17(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-hover-card': 1.1.16(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-label': 2.1.9(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-navigation-menu': 1.2.15(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-popover': 1.1.16(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-progress': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-radio-group': 1.4.0(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-scroll-area': 1.2.11(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-select': 2.3.0(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-separator': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.5(@types/react@18.3.31)(react@19.2.6) + '@radix-ui/react-switch': 1.3.0(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-tabs': 1.1.14(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-toast': 1.2.16(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-tooltip': 1.2.9(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/default-layout': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf/renderer': 4.5.1(react@19.2.6) + '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@18.3.31)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + '@tabler/icons-react': 3.44.0(react@19.2.6) + '@tailwindcss/vite': 4.3.0(vite@5.4.21(@types/node@24.13.1)(lightningcss@1.32.0)(terser@5.48.0)) + '@tanstack/react-query': 5.101.0(react@19.2.6) + '@tanstack/react-query-devtools': 5.101.0(@tanstack/react-query@5.101.0(react@19.2.6))(react@19.2.6) + '@tanstack/react-table': 8.21.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@tinymce/tinymce-react': 6.3.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tinymce@7.9.3) + '@types/dompurify': 3.2.0 + '@types/node': 24.13.1 + '@types/tinymce': 4.6.9 + axios: 1.17.0 + class-variance-authority: 0.7.1 + clsx: 2.1.1 + cmdk: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + date-fns: 3.6.0 + dayjs: 1.11.21 + dompurify: 3.4.8 + ethiopian-calendar-date-converter: 2.1.6 + ethiopian-calendar-new: 1.1.0 + file-type: 18.7.0 + framer-motion: 12.40.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + html2canvas: 1.4.1 + i18next: 25.10.10(typescript@5.9.3) + i18next-browser-languagedetector: 8.2.1 + jquery: 3.7.1 + js-cookie: 3.0.8 + jspdf: 3.0.4 + lodash: 4.18.1 + lucide-react: 0.513.0(react@19.2.6) + mantine-react-table: 2.0.0-beta.9(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/dates@7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(dayjs@1.11.21)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(@tabler/icons-react@3.44.0(react@19.2.6))(clsx@2.1.1)(dayjs@1.11.21)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + mui-ethiopian-datepicker: 0.3.2(4b3af212eafdf0059f009b005d7e343d) + next-themes: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + path: 0.12.7 + pdf-lib: 1.17.1 + qs: 6.15.2 + react: 19.2.6 + react-cookie: 8.1.2(@types/react@18.3.31)(react@19.2.6) + react-css-nocode-editor: 1.0.13(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6) + react-day-picker: 8.10.2(date-fns@3.6.0)(react@19.2.6) + react-dom: 19.2.6(react@19.2.6) + react-dropzone: 14.4.1(react@19.2.6) + react-hook-form: 7.77.0(react@19.2.6) + react-i18next: 15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(typescript@5.9.3) + react-icons: 5.6.0(react@19.2.6) + react-image-crop: 11.0.10(react@19.2.6) + react-intersection-observer: 9.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-pdf: 10.4.1(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-pdf-html: 2.1.5(@react-pdf/renderer@4.5.1(react@19.2.6))(react@19.2.6) + react-redux: 9.3.0(@types/react@18.3.31)(react@19.2.6)(redux@5.0.1) + react-resizable-panels: 3.0.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router-dom: 7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-signature-canvas: 1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.31)(prop-types@15.8.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + recharts: 3.8.1(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6)(redux@5.0.1) + rollup-plugin-visualizer: 7.0.1(rollup@4.61.1) + socket.io-client: 4.8.3 + sonner: 2.0.7(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + tailwind-merge: 3.6.0 + tailwind-scrollbar-hide: 4.0.0(tailwindcss@4.3.0) + tailwindcss: 4.3.0 + tailwindcss-animate: 1.0.7(tailwindcss@4.3.0) + tinymce: 7.9.3 + url: 0.11.4 + vaul: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + xlsx: 0.18.5 + zod: 3.25.76 + transitivePeerDependencies: + - '@babel/core' + - '@emotion/is-prop-valid' + - '@mui/icons-material' + - '@mui/material' + - '@mui/x-date-pickers' + - '@types/prop-types' + - '@types/react' + - '@types/react-dom' + - bufferutil + - debug + - pdfjs-dist + - prop-types + - react-is + - react-native + - redux + - rolldown + - rollup + - supports-color + - typescript + - utf-8-validate + - vite + '@ts-morph/common@0.27.0': dependencies: fast-glob: 3.3.3 @@ -18465,7 +18630,7 @@ snapshots: '@typescript-eslint/types': 8.60.1 '@typescript-eslint/typescript-estree': 8.60.1(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.60.1 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) eslint: 8.57.1 typescript: 5.9.3 transitivePeerDependencies: @@ -18475,7 +18640,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.60.1(typescript@5.9.3) '@typescript-eslint/types': 8.60.1 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -18494,7 +18659,7 @@ snapshots: '@typescript-eslint/types': 8.60.1 '@typescript-eslint/typescript-estree': 8.60.1(typescript@5.9.3) '@typescript-eslint/utils': 8.60.1(eslint@8.57.1)(typescript@5.9.3) - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) eslint: 8.57.1 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 @@ -18509,7 +18674,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.60.1(typescript@5.9.3) '@typescript-eslint/types': 8.60.1 '@typescript-eslint/visitor-keys': 8.60.1 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) minimatch: 10.2.5 semver: 7.8.2 tinyglobby: 0.2.17 @@ -18798,7 +18963,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -19307,6 +19472,16 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-styled-components@2.3.0(styled-components@5.3.11(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6))(supports-color@5.5.0): + dependencies: + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-module-imports': 7.29.7(supports-color@5.5.0) + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) + picomatch: 4.0.4 + styled-components: 5.3.11(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6) + transitivePeerDependencies: + - supports-color + babel-polyfill@6.26.0: dependencies: babel-runtime: 6.26.0 @@ -19462,7 +19637,7 @@ snapshots: dependencies: bytes: 3.1.2 content-type: 1.0.5 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 @@ -20511,7 +20686,7 @@ snapshots: engine.io-client@6.6.5: dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) engine.io-parser: 5.2.3 ws: 8.20.1 xmlhttprequest-ssl: 2.1.2 @@ -20531,7 +20706,7 @@ snapshots: base64id: 2.0.0 cookie: 0.7.2 cors: 2.8.6 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) engine.io-parser: 5.2.3 ws: 8.21.0 transitivePeerDependencies: @@ -20762,7 +20937,7 @@ snapshots: eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) eslint: 8.57.1 get-tsconfig: 4.14.0 is-bun-module: 2.0.0 @@ -20890,7 +21065,7 @@ snapshots: ajv: 6.15.0 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -21127,7 +21302,7 @@ snapshots: content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 @@ -21180,7 +21355,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -21335,7 +21510,7 @@ snapshots: finalhandler@2.1.1: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -21583,7 +21758,7 @@ snapshots: dependencies: basic-ftp: 5.3.1 data-uri-to-buffer: 6.0.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -21892,7 +22067,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -21905,14 +22080,14 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -22352,7 +22527,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -23012,7 +23187,7 @@ snapshots: dependencies: chalk: 5.6.2 commander: 13.1.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) execa: 8.0.1 lilconfig: 3.1.3 listr2: 8.3.3 @@ -23699,7 +23874,7 @@ snapshots: micromark@4.0.2: dependencies: '@types/debug': 4.1.13 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -24225,7 +24400,7 @@ snapshots: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) get-uri: 6.0.5 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 @@ -24575,7 +24750,7 @@ snapshots: proxy-agent@6.5.0: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 lru-cache: 7.18.3 @@ -24604,7 +24779,7 @@ snapshots: dependencies: '@puppeteer/browsers': 2.13.2 chromium-bidi: 14.0.0(devtools-protocol@0.0.1608973) - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) devtools-protocol: 0.0.1608973 typed-query-selector: 2.12.2 webdriver-bidi-protocol: 0.4.1 @@ -24857,6 +25032,15 @@ snapshots: - '@babel/core' - react-is + react-css-nocode-editor@1.0.13(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6): + dependencies: + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + styled-components: 5.3.11(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6) + transitivePeerDependencies: + - '@babel/core' + - react-is + react-day-picker@8.10.2(date-fns@3.6.0)(react@19.2.6): dependencies: date-fns: 3.6.0 @@ -25467,7 +25651,7 @@ snapshots: router@2.2.0: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 @@ -25589,7 +25773,7 @@ snapshots: send@1.2.1: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -25805,7 +25989,7 @@ snapshots: socket.io-adapter@2.5.8: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) ws: 8.21.0 transitivePeerDependencies: - bufferutil @@ -25815,7 +25999,7 @@ snapshots: socket.io-client@4.8.3: dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) engine.io-client: 6.6.5 socket.io-parser: 4.2.6 transitivePeerDependencies: @@ -25826,7 +26010,7 @@ snapshots: socket.io-parser@4.2.6: dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -25835,7 +26019,7 @@ snapshots: accepts: 1.3.8 base64id: 2.0.0 cors: 2.8.6 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) engine.io: 6.6.9 socket.io-adapter: 2.5.8 socket.io-parser: 4.2.6 @@ -25847,7 +26031,7 @@ snapshots: socks-proxy-agent@8.0.5: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) socks: 2.8.9 transitivePeerDependencies: - supports-color @@ -26142,6 +26326,24 @@ snapshots: transitivePeerDependencies: - '@babel/core' + styled-components@5.3.11(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6): + dependencies: + '@babel/helper-module-imports': 7.29.7(supports-color@5.5.0) + '@babel/traverse': 7.29.7(supports-color@5.5.0) + '@emotion/is-prop-valid': 1.4.0 + '@emotion/stylis': 0.8.5 + '@emotion/unitless': 0.7.5 + babel-plugin-styled-components: 2.3.0(styled-components@5.3.11(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6))(supports-color@5.5.0) + css-to-react-native: 3.2.0 + hoist-non-react-statics: 3.3.2 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-is: 19.2.7 + shallowequal: 1.1.0 + supports-color: 5.5.0 + transitivePeerDependencies: + - '@babel/core' + styled-jsx@5.1.1(babel-plugin-macros@3.1.0)(react@18.3.1): dependencies: client-only: 0.0.1 @@ -26167,7 +26369,7 @@ snapshots: dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) fast-safe-stringify: 2.1.1 form-data: 4.0.5 formidable: 3.5.4 @@ -26680,7 +26882,7 @@ snapshots: app-root-path: 3.1.0 buffer: 6.0.3 dayjs: 1.11.21 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) dedent: 1.7.2(babel-plugin-macros@3.1.0) dotenv: 16.6.1 glob: 10.5.0 @@ -26704,7 +26906,7 @@ snapshots: app-root-path: 3.1.0 buffer: 6.0.3 dayjs: 1.11.21 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) dedent: 1.7.2(babel-plugin-macros@3.1.0) dotenv: 16.6.1 glob: 10.5.0 @@ -27065,7 +27267,7 @@ snapshots: vite-node@2.1.9(@types/node@22.20.1)(lightningcss@1.32.0)(terser@5.48.0): dependencies: cac: 6.7.14 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) es-module-lexer: 1.7.0 pathe: 1.1.2 vite: 5.4.21(@types/node@22.20.1)(lightningcss@1.32.0)(terser@5.48.0) @@ -27083,7 +27285,7 @@ snapshots: vite-node@2.1.9(@types/node@24.13.1)(lightningcss@1.32.0)(terser@5.48.0): dependencies: cac: 6.7.14 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) es-module-lexer: 1.7.0 pathe: 1.1.2 vite: 5.4.21(@types/node@24.13.1)(lightningcss@1.32.0)(terser@5.48.0) @@ -27130,7 +27332,7 @@ snapshots: '@vitest/spy': 2.1.9 '@vitest/utils': 2.1.9 chai: 5.3.3 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) expect-type: 1.3.0 magic-string: 0.30.21 pathe: 1.1.2 @@ -27166,7 +27368,7 @@ snapshots: '@vitest/spy': 2.1.9 '@vitest/utils': 2.1.9 chai: 5.3.3 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) expect-type: 1.3.0 magic-string: 0.30.21 pathe: 1.1.2