From 833cf3b4b87f8c45d5dea4b0ddff0d02eddbd110 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Fri, 5 Dec 2025 09:34:19 +0000 Subject: [PATCH] feat: Update organization member management and bulk invite functionality - Marked the status of "Invite and Manage Team Members" story as Complete in README. - Updated the status of ORG-002 to Complete in the corresponding markdown file. - Modified OrganizationManager to assign roles as 'owner' during organization creation. - Implemented bulk invitation feature in UserInvitationManager, allowing multiple users to be invited via CSV upload. - Added IReq_BulkCreateInvitations interface for bulk invitation requests. - Enhanced CreateOrgForm to update state with new roles upon organization creation. - Introduced BulkInviteModal for bulk inviting users, including email validation and role assignment. - Updated UsersView to support ownership transfer and bulk invitation functionality. - Improved account state management to handle new roles and organizations. --- package.json | 4 +- pnpm-lock.yaml | 708 ++++++------------ stories/README.md | 4 +- .../ORG-002-member-management.md | 6 +- ts/reception/classes.organizationmanager.ts | 5 +- ts/reception/classes.userinvitationmanager.ts | 161 ++++ .../request/loint-reception.userinvitation.ts | 36 + ts_web/elements/account/bulk-invite-modal.ts | 585 +++++++++++++++ ts_web/elements/account/create-org-modal.ts | 5 +- ts_web/elements/account/views/usersview.ts | 143 +++- ts_web/states/accountstate.ts | 3 + 11 files changed, 1148 insertions(+), 512 deletions(-) create mode 100644 ts_web/elements/account/bulk-invite-modal.ts diff --git a/package.json b/package.json index c77814c..053daee 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,9 @@ "author": "Task Venture Capital GmbH", "license": "MIT", "dependencies": { - "@api.global/typedrequest": "^3.1.11", + "@api.global/typedrequest": "^3.2.5", "@api.global/typedrequest-interfaces": "^3.0.19", - "@api.global/typedserver": "^7.7.0", + "@api.global/typedserver": "^7.8.17", "@api.global/typedsocket": "^4.1.0", "@consent.software/catalog": "^2.0.1", "@design.estate/dees-catalog": "^2.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f58e172..fa30fc3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,14 +9,14 @@ importers: .: dependencies: '@api.global/typedrequest': - specifier: ^3.1.11 - version: 3.1.11 + specifier: ^3.2.5 + version: 3.2.5 '@api.global/typedrequest-interfaces': specifier: ^3.0.19 version: 3.0.19 '@api.global/typedserver': - specifier: ^7.7.0 - version: 7.7.0 + specifier: ^7.8.17 + version: 7.8.17(@tiptap/pm@2.27.1) '@api.global/typedsocket': specifier: ^4.1.0 version: 4.1.0(@push.rocks/smartserve@1.1.2) @@ -129,14 +129,14 @@ packages: '@api.global/typedrequest-interfaces@3.0.19': resolution: {integrity: sha512-uuHUXJeOy/inWSDrwD0Cwax2rovpxYllDhM2RWh+6mVpQuNmZ3uw6IVg6dA2G1rOe24Ebs+Y9SzEogo+jYN7vw==} - '@api.global/typedrequest@3.1.11': - resolution: {integrity: sha512-j8EO3na0WMw8pFkAfEaEui2a4TaAL1G/dv1CYl8LEPXckSKkl1BCAS1kFOW2xuI9pwZkmSqlo3xpQ3KmkmHaGQ==} + '@api.global/typedrequest@3.2.5': + resolution: {integrity: sha512-LM/sUTuYnU5xY4gNZrN6ERMiKr+SpDZuSxJkAZz1YazC7ymGfo6uQ8sCnN8eNNQNFqIOkC+BtfYRayfbGwYLLg==} '@api.global/typedserver@3.0.80': resolution: {integrity: sha512-dcp0oXsjBL+XdFg1wUUP08uJQid5bQ0Yv3V3Y3lnI2QCbat0FU+Tsb0TZRnZ4+P150Vj/ITBqJUgDzFsF34grA==} - '@api.global/typedserver@7.7.0': - resolution: {integrity: sha512-32GKI3M3HVFQw30T9SszyjAciXjQsLDbm7KUmBsllJoamUZsE9tb6Fdgk2uc3TQziUiFOpq3tYllhj72oNLy3A==} + '@api.global/typedserver@7.8.17': + resolution: {integrity: sha512-I4aA8l2f43HP70dZTEqOyWiDcolFsZm6/0d3B7lYq/DwzorV4IJZ0ZO18jHyGHZuaaJri4m5j3Wt7dn6yHDY3A==} '@api.global/typedsocket@3.1.1': resolution: {integrity: sha512-Wkz3NlhmfdZMKqXXI2c2dMtGGmSmhdOegZiziL+9b2mqPYdc7Gd8AZRdEOKvbSoIvc9G22/5BEadIWHrfq66TA==} @@ -174,48 +174,48 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - '@aws-sdk/client-s3@3.940.0': - resolution: {integrity: sha512-Wi4qnBT6shRRMXuuTgjMFTU5mu2KFWisgcigEMPptjPGUtJvBVi4PTGgS64qsLoUk/obqDAyOBOfEtRZ2ddC2w==} + '@aws-sdk/client-s3@3.943.0': + resolution: {integrity: sha512-UOX8/1mmNaRmEkxoIVP2+gxd5joPJqz+fygRqlIXON1cETLGoctinMwQs7qU8g8hghm76TU2G6ZV6sLH8cySMw==} engines: {node: '>=18.0.0'} - '@aws-sdk/client-sso@3.940.0': - resolution: {integrity: sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A==} + '@aws-sdk/client-sso@3.943.0': + resolution: {integrity: sha512-kOTO2B8Ks2qX73CyKY8PAajtf5n39aMe2spoiOF5EkgSzGV7hZ/HONRDyADlyxwfsX39Q2F2SpPUaXzon32IGw==} engines: {node: '>=18.0.0'} - '@aws-sdk/core@3.940.0': - resolution: {integrity: sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA==} + '@aws-sdk/core@3.943.0': + resolution: {integrity: sha512-8CBy2hI9ABF7RBVQuY1bgf/ue+WPmM/hl0adrXFlhnhkaQP0tFY5zhiy1Y+n7V+5f3/ORoHBmCCQmcHDDYJqJQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-env@3.940.0': - resolution: {integrity: sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw==} + '@aws-sdk/credential-provider-env@3.943.0': + resolution: {integrity: sha512-WnS5w9fK9CTuoZRVSIHLOMcI63oODg9qd1vXMYb7QGLGlfwUm4aG3hdu7i9XvYrpkQfE3dzwWLtXF4ZBuL1Tew==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-http@3.940.0': - resolution: {integrity: sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ==} + '@aws-sdk/credential-provider-http@3.943.0': + resolution: {integrity: sha512-SA8bUcYDEACdhnhLpZNnWusBpdmj4Vl67Vxp3Zke7SvoWSYbuxa+tiDiC+c92Z4Yq6xNOuLPW912ZPb9/NsSkA==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-ini@3.940.0': - resolution: {integrity: sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw==} + '@aws-sdk/credential-provider-ini@3.943.0': + resolution: {integrity: sha512-BcLDb8l4oVW+NkuqXMlO7TnM6lBOWW318ylf4FRED/ply5eaGxkQYqdGvHSqGSN5Rb3vr5Ek0xpzSjeYD7C8Kw==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-login@3.940.0': - resolution: {integrity: sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg==} + '@aws-sdk/credential-provider-login@3.943.0': + resolution: {integrity: sha512-9iCOVkiRW+evxiJE94RqosCwRrzptAVPhRhGWv4osfYDhjNAvUMyrnZl3T1bjqCoKNcETRKEZIU3dqYHnUkcwQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-node@3.940.0': - resolution: {integrity: sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g==} + '@aws-sdk/credential-provider-node@3.943.0': + resolution: {integrity: sha512-14eddaH/gjCWoLSAELVrFOQNyswUYwWphIt+PdsJ/FqVfP4ay2HsiZVEIYbQtmrKHaoLJhiZKwBQRjcqJDZG0w==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-process@3.940.0': - resolution: {integrity: sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ==} + '@aws-sdk/credential-provider-process@3.943.0': + resolution: {integrity: sha512-GIY/vUkthL33AdjOJ8r9vOosKf/3X+X7LIiACzGxvZZrtoOiRq0LADppdiKIB48vTL63VvW+eRIOFAxE6UDekw==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-sso@3.940.0': - resolution: {integrity: sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw==} + '@aws-sdk/credential-provider-sso@3.943.0': + resolution: {integrity: sha512-1c5G11syUrru3D9OO6Uk+ul5e2lX1adb+7zQNyluNaLPXP6Dina6Sy6DFGRLu7tM8+M7luYmbS3w63rpYpaL+A==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-web-identity@3.940.0': - resolution: {integrity: sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w==} + '@aws-sdk/credential-provider-web-identity@3.943.0': + resolution: {integrity: sha512-VtyGKHxICSb4kKGuaqotxso8JVM8RjCS3UYdIMOxUt9TaFE/CZIfZKtjTr+IJ7M0P7t36wuSUb/jRLyNmGzUUA==} engines: {node: '>=18.0.0'} '@aws-sdk/middleware-bucket-endpoint@3.936.0': @@ -226,8 +226,8 @@ packages: resolution: {integrity: sha512-Eb4ELAC23bEQLJmUMYnPWcjD3FZIsmz2svDiXEcxRkQU9r7NRID7pM7C5NPH94wOfiCk0b2Y8rVyFXW0lGQwbA==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-flexible-checksums@3.940.0': - resolution: {integrity: sha512-WdsxDAVj5qaa5ApAP+JbpCOMHFGSmzjs2Y2OBSbWPeR9Ew7t/Okj+kUub94QJPsgzhvU1/cqNejhsw5VxeFKSQ==} + '@aws-sdk/middleware-flexible-checksums@3.943.0': + resolution: {integrity: sha512-J2oYbAQXTFEezs5m2Vij6H3w71K1hZfCtb85AsR/2Ovp/FjABMnK+Es1g1edRx6KuMTc9HkL/iGU4e+ek+qCZw==} engines: {node: '>=18.0.0'} '@aws-sdk/middleware-host-header@3.936.0': @@ -246,32 +246,32 @@ packages: resolution: {integrity: sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-sdk-s3@3.940.0': - resolution: {integrity: sha512-JYkLjgS1wLoKHJ40G63+afM1ehmsPsjcmrHirKh8+kSCx4ip7+nL1e/twV4Zicxr8RJi9Y0Ahq5mDvneilDDKQ==} + '@aws-sdk/middleware-sdk-s3@3.943.0': + resolution: {integrity: sha512-kd2mALfthU+RS9NsPS+qvznFcPnVgVx9mgmStWCPn5Qc5BTnx4UAtm+HPA+XZs+zxOopp+zmAfE4qxDHRVONBA==} engines: {node: '>=18.0.0'} '@aws-sdk/middleware-ssec@3.936.0': resolution: {integrity: sha512-/GLC9lZdVp05ozRik5KsuODR/N7j+W+2TbfdFL3iS+7un+gnP6hC8RDOZd6WhpZp7drXQ9guKiTAxkZQwzS8DA==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-user-agent@3.940.0': - resolution: {integrity: sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA==} + '@aws-sdk/middleware-user-agent@3.943.0': + resolution: {integrity: sha512-956n4kVEwFNXndXfhSAN5wO+KRgqiWEEY+ECwLvxmmO8uQ0NWOa8l6l65nTtyuiWzMX81c9BvlyNR5EgUeeUvA==} engines: {node: '>=18.0.0'} - '@aws-sdk/nested-clients@3.940.0': - resolution: {integrity: sha512-x0mdv6DkjXqXEcQj3URbCltEzW6hoy/1uIL+i8gExP6YKrnhiZ7SzuB4gPls2UOpK5UqLiqXjhRLfBb1C9i4Dw==} + '@aws-sdk/nested-clients@3.943.0': + resolution: {integrity: sha512-anFtB0p2FPuyUnbOULwGmKYqYKSq1M73c9uZ08jR/NCq6Trjq9cuF5TFTeHwjJyPRb4wMf2Qk859oiVfFqnQiw==} engines: {node: '>=18.0.0'} '@aws-sdk/region-config-resolver@3.936.0': resolution: {integrity: sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw==} engines: {node: '>=18.0.0'} - '@aws-sdk/signature-v4-multi-region@3.940.0': - resolution: {integrity: sha512-ugHZEoktD/bG6mdgmhzLDjMP2VrYRAUPRPF1DpCyiZexkH7DCU7XrSJyXMvkcf0DHV+URk0q2sLf/oqn1D2uYw==} + '@aws-sdk/signature-v4-multi-region@3.943.0': + resolution: {integrity: sha512-KKvmxNQ/FZbM6ml6nKd8ltDulsUojsXnMJNgf1VHTcJEbADC/6mVWOq0+e9D0WP1qixUBEuMjlS2HqD5KoqwEg==} engines: {node: '>=18.0.0'} - '@aws-sdk/token-providers@3.940.0': - resolution: {integrity: sha512-k5qbRe/ZFjW9oWEdzLIa2twRVIEx7p/9rutofyrRysrtEnYh3HAWCngAnwbgKMoiwa806UzcTRx0TjyEpnKcCg==} + '@aws-sdk/token-providers@3.943.0': + resolution: {integrity: sha512-cRKyIzwfkS+XztXIFPoWORuaxlIswP+a83BJzelX4S1gUZ7FcXB4+lj9Jxjn8SbQhR4TPU3Owbpu+S7pd6IRbQ==} engines: {node: '>=18.0.0'} '@aws-sdk/types@3.936.0': @@ -293,8 +293,8 @@ packages: '@aws-sdk/util-user-agent-browser@3.936.0': resolution: {integrity: sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw==} - '@aws-sdk/util-user-agent-node@3.940.0': - resolution: {integrity: sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A==} + '@aws-sdk/util-user-agent-node@3.943.0': + resolution: {integrity: sha512-gn+ILprVRrgAgTIBk2TDsJLRClzIOdStQFeFTcN0qpL8Z4GBCqMFhw7O7X+MM55Stt5s4jAauQ/VvoqmCADnQg==} engines: {node: '>=18.0.0'} peerDependencies: aws-crt: '>=1.0.0' @@ -306,8 +306,8 @@ packages: resolution: {integrity: sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA==} engines: {node: '>=18.0.0'} - '@aws/lambda-invoke-store@0.2.1': - resolution: {integrity: sha512-sIyFcoPZkTtNu9xFeEoynMef3bPJIAbOfUh+ueYcfhVl6xm2VRtMcMclSxmZCMnHHd4hlYKJeq/aggmBEWynww==} + '@aws/lambda-invoke-store@0.2.2': + resolution: {integrity: sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg==} engines: {node: '>=18.0.0'} '@babel/runtime@7.28.4': @@ -320,6 +320,9 @@ packages: '@cloudflare/workers-types@4.20251202.0': resolution: {integrity: sha512-Q7m1Ivu2fbKalOPm00KLpu6GfRaq4TlrPknqugvZgp/gDH96OYKINO4x7jvCIBvCz/aK9vVoOj8tlbSQBervVA==} + '@cloudflare/workers-types@4.20251205.0': + resolution: {integrity: sha512-7pup7fYkuQW5XD8RUS/vkxF9SXlrGyCXuZ4ro3uVQvca/GTeSa+8bZ8T4wbq1Aea5lmLIGSlKbhl2msME7bRBA==} + '@configvault.io/interfaces@1.0.17': resolution: {integrity: sha512-bEcCUR2VBDJsTin8HQh8Uw/mlYl2v8A3jMIaQ+MTB9Hrqd6CZL2dL7iJdWyFl/3EIX+LDxWFR+Oq7liIq7w+1Q==} @@ -338,6 +341,9 @@ packages: '@design.estate/dees-comms@1.0.27': resolution: {integrity: sha512-GvzTUwkV442LD60T08iqSoqvhA02Mou5lFvvqBPc4yBUiU7cZISqBx+76xvMgMIEI9Dx9JfTl4/2nW8MoVAanw==} + '@design.estate/dees-comms@1.0.30': + resolution: {integrity: sha512-KchMlklJfKAjQiJiR0xmofXtQ27VgZtBIxcMwPE9d+h3jJRv+lPZxzBQVOM0eyM0uS44S5vJMZ11IeV4uDXSHg==} + '@design.estate/dees-domtools@2.3.6': resolution: {integrity: sha512-cKaPNtSpp/ZuuXVx2dXO3K2FU3/HjC4ZkqtXb8Kl6yy9rNDbgtjcI4PuOk9Ux1SJzw7FgcxqVh7OSEV60htbmg==} @@ -356,312 +362,156 @@ packages: '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.27.1': resolution: {integrity: sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.27.1': resolution: {integrity: sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.27.1': resolution: {integrity: sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.27.1': resolution: {integrity: sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.27.1': resolution: {integrity: sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.27.1': resolution: {integrity: sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.27.1': resolution: {integrity: sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.27.1': resolution: {integrity: sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.27.1': resolution: {integrity: sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.27.1': resolution: {integrity: sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.27.1': resolution: {integrity: sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.27.1': resolution: {integrity: sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.27.1': resolution: {integrity: sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.27.1': resolution: {integrity: sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.27.1': resolution: {integrity: sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.27.1': resolution: {integrity: sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.27.1': resolution: {integrity: sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.27.1': resolution: {integrity: sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.27.1': resolution: {integrity: sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.27.1': resolution: {integrity: sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.27.1': resolution: {integrity: sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - '@esbuild/openharmony-arm64@0.27.1': resolution: {integrity: sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.27.1': resolution: {integrity: sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.27.1': resolution: {integrity: sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.27.1': resolution: {integrity: sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.27.1': resolution: {integrity: sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==} engines: {node: '>=18'} @@ -971,9 +821,6 @@ packages: '@push.rocks/smartfile@13.1.0': resolution: {integrity: sha512-bSjH9vHl6l1nbe/gcSi4PcutFcTHUCVkMuQGGTVtn1cOgCuOXIHV04uhOXrZoKvlcSxxoiq8THolFt65lqn7cg==} - '@push.rocks/smartfs@1.1.2': - resolution: {integrity: sha512-zk2RaflQMKoQa7ct1l/+dTtgBsW6cZI151H1H6TLrqKncyHETYBJBKdFL/cJTJKXvvi9jYhb/j7c5kDLCYX+7Q==} - '@push.rocks/smartfs@1.2.0': resolution: {integrity: sha512-1R47jJZwX869z7DYgKeAZKTU1SbGnM7W/ZmgsI7AkQQhiascNqY3/gF4V5kIprmuf1WhpRbCbZyum8s7J1LDdg==} @@ -1351,8 +1198,8 @@ packages: resolution: {integrity: sha512-ezHLe1tKLUxDJo2LHtDuEDyWXolw8WGOR92qb4bQdWq/zKenO5BvctZGrVJBK08zjezSk7bmbKFOXIVyChvDLw==} engines: {node: '>=18.0.0'} - '@smithy/core@3.18.5': - resolution: {integrity: sha512-6gnIz3h+PEPQGDj8MnRSjDvKBah042jEoPgjFGJ4iJLBE78L4lY/n98x14XyPF4u3lN179Ub/ZKFY5za9GeLQw==} + '@smithy/core@3.18.7': + resolution: {integrity: sha512-axG9MvKhMWOhFbvf5y2DuyTxQueO0dkedY9QC3mAfndLosRI/9LJv8WaL0mw7ubNhsO4IuXX9/9dYGPFvHrqlw==} engines: {node: '>=18.0.0'} '@smithy/credential-provider-imds@4.2.5': @@ -1415,12 +1262,12 @@ packages: resolution: {integrity: sha512-Y/RabVa5vbl5FuHYV2vUCwvh/dqzrEY/K2yWPSqvhFUwIY0atLqO4TienjBXakoy4zrKAMCZwg+YEqmH7jaN7A==} engines: {node: '>=18.0.0'} - '@smithy/middleware-endpoint@4.3.12': - resolution: {integrity: sha512-9pAX/H+VQPzNbouhDhkW723igBMLgrI8OtX+++M7iKJgg/zY/Ig3i1e6seCcx22FWhE6Q/S61BRdi2wXBORT+A==} + '@smithy/middleware-endpoint@4.3.14': + resolution: {integrity: sha512-v0q4uTKgBM8dsqGjqsabZQyH85nFaTnFcgpWU1uydKFsdyyMzfvOkNum9G7VK+dOP01vUnoZxIeRiJ6uD0kjIg==} engines: {node: '>=18.0.0'} - '@smithy/middleware-retry@4.4.12': - resolution: {integrity: sha512-S4kWNKFowYd0lID7/DBqWHOQxmxlsf0jBaos9chQZUWTVOjSW1Ogyh8/ib5tM+agFDJ/TCxuCTvrnlc+9cIBcQ==} + '@smithy/middleware-retry@4.4.14': + resolution: {integrity: sha512-Z2DG8Ej7FyWG1UA+7HceINtSLzswUgs2np3sZX0YBBxCt+CXG4QUxv88ZDS3+2/1ldW7LqtSY1UO/6VQ1pND8Q==} engines: {node: '>=18.0.0'} '@smithy/middleware-serde@4.2.6': @@ -1467,8 +1314,8 @@ packages: resolution: {integrity: sha512-xSUfMu1FT7ccfSXkoLl/QRQBi2rOvi3tiBZU2Tdy3I6cgvZ6SEi9QNey+lqps/sJRnogIS+lq+B1gxxbra2a/w==} engines: {node: '>=18.0.0'} - '@smithy/smithy-client@4.9.8': - resolution: {integrity: sha512-8xgq3LgKDEFoIrLWBho/oYKyWByw9/corz7vuh1upv7ZBm0ZMjGYBhbn6v643WoIqA9UTcx5A5htEp/YatUwMA==} + '@smithy/smithy-client@4.9.10': + resolution: {integrity: sha512-Jaoz4Jw1QYHc1EFww/E6gVtNjhoDU+gwRKqXP6C3LKYqqH2UQhP8tMP3+t/ePrhaze7fhLE8vS2q6vVxBANFTQ==} engines: {node: '>=18.0.0'} '@smithy/types@4.9.0': @@ -1503,12 +1350,12 @@ packages: resolution: {integrity: sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-browser@4.3.11': - resolution: {integrity: sha512-yHv+r6wSQXEXTPVCIQTNmXVWs7ekBTpMVErjqZoWkYN75HIFN5y9+/+sYOejfAuvxWGvgzgxbTHa/oz61YTbKw==} + '@smithy/util-defaults-mode-browser@4.3.13': + resolution: {integrity: sha512-hlVLdAGrVfyNei+pKIgqDTxfu/ZI2NSyqj4IDxKd5bIsIqwR/dSlkxlPaYxFiIaDVrBy0he8orsFy+Cz119XvA==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-node@4.2.14': - resolution: {integrity: sha512-ljZN3iRvaJUgulfvobIuG97q1iUuCMrvXAlkZ4msY+ZuVHQHDIqn7FKZCEj+bx8omz6kF5yQXms/xhzjIO5XiA==} + '@smithy/util-defaults-mode-node@4.2.16': + resolution: {integrity: sha512-F1t22IUiJLHrxW9W1CQ6B9PN+skZ9cqSuzB18Eh06HrJPbjsyZ7ZHecAKw80DQtyGTRcVfeukKaCRYebFwclbg==} engines: {node: '>=18.0.0'} '@smithy/util-endpoints@3.2.5': @@ -2279,11 +2126,6 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.27.1: resolution: {integrity: sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==} engines: {node: '>=18'} @@ -2655,15 +2497,15 @@ packages: jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} - jsonwebtoken@9.0.2: - resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + jsonwebtoken@9.0.3: + resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} engines: {node: '>=12', npm: '>=6'} - jwa@1.4.2: - resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==} + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} - jws@3.2.2: - resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -2775,8 +2617,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.2: - resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} + lru-cache@11.2.4: + resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} engines: {node: 20 || >=22} lucide@0.555.0: @@ -3013,12 +2855,12 @@ packages: resolution: {integrity: sha512-irhhjRVLE20hbkRl4zpAYLnDMM+zIZnp0IDB9akAFFUZp/3XdOfwwddc7y6cNvF2WCEtfTYRwYbIfYa2kVY0og==} engines: {node: '>=20.19.0'} - mongodb-memory-server-core@10.3.0: - resolution: {integrity: sha512-tp+ZfTBAPqHXjROhAFg6HcVVzXaEhh/iHcbY7QPOIiLwr94OkBFAw4pixyGSfP5wI2SZeEA13lXyRmBAhugWgA==} + mongodb-memory-server-core@10.4.1: + resolution: {integrity: sha512-YJdrEyF9hk64nfeoVDMP6IfTzK+gLZhrQqYyP6JJMsqo2LK5eF7JRZ4YPQDmt1re/JhItpiU+ypiZbIG1OsW5Q==} engines: {node: '>=16.20.1'} - mongodb-memory-server@10.3.0: - resolution: {integrity: sha512-dRNr2uEhMgjEe6kgqS+ITBKBbl2cz0DNBjNZ12BGUckvEOAHbhd3R7q/lFPSZrZ6AMKa2EOUJdAmFF1WlqSbsA==} + mongodb-memory-server@10.4.1: + resolution: {integrity: sha512-XpCyV1e7QQ1lW28rgtXP4ZlX8ZfD/8z1ZGNxz2y3JrosLgDrNnYWvPjlgFj3JjboYUtlh1jF2Ez/rwsQA6cl0w==} engines: {node: '>=16.20.1'} mongodb@6.21.0: @@ -3101,8 +2943,8 @@ packages: no-case@2.3.2: resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==} - node-forge@1.3.2: - resolution: {integrity: sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw==} + node-forge@1.3.3: + resolution: {integrity: sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==} engines: {node: '>= 6.13.0'} normalize-newline@4.1.0: @@ -3627,8 +3469,8 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsx@4.20.6: - resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} engines: {node: '>=18.0.0'} hasBin: true @@ -3824,7 +3666,7 @@ snapshots: '@api.global/typedrequest-interfaces@3.0.19': {} - '@api.global/typedrequest@3.1.11': + '@api.global/typedrequest@3.2.5': dependencies: '@api.global/typedrequest-interfaces': 3.0.19 '@push.rocks/isounique': 1.0.5 @@ -3838,7 +3680,7 @@ snapshots: '@api.global/typedserver@3.0.80(@push.rocks/smartserve@1.1.2)': dependencies: - '@api.global/typedrequest': 3.1.11 + '@api.global/typedrequest': 3.2.5 '@api.global/typedrequest-interfaces': 3.0.19 '@api.global/typedsocket': 3.1.1(@push.rocks/smartserve@1.1.2) '@cloudflare/workers-types': 4.20251202.0 @@ -3884,13 +3726,14 @@ snapshots: - utf-8-validate - vue - '@api.global/typedserver@7.7.0': + '@api.global/typedserver@7.8.17(@tiptap/pm@2.27.1)': dependencies: - '@api.global/typedrequest': 3.1.11 + '@api.global/typedrequest': 3.2.5 '@api.global/typedrequest-interfaces': 3.0.19 '@api.global/typedsocket': 4.1.0(@push.rocks/smartserve@1.1.2) - '@cloudflare/workers-types': 4.20251202.0 - '@design.estate/dees-comms': 1.0.27 + '@cloudflare/workers-types': 4.20251205.0 + '@design.estate/dees-catalog': 2.0.3(@tiptap/pm@2.27.1) + '@design.estate/dees-comms': 1.0.30 '@push.rocks/lik': 6.2.2 '@push.rocks/smartdelay': 3.0.5 '@push.rocks/smartenv': 6.0.0 @@ -3922,6 +3765,7 @@ snapshots: lit: 3.3.1 transitivePeerDependencies: - '@nuxt/kit' + - '@tiptap/pm' - bufferutil - react - supports-color @@ -3930,7 +3774,7 @@ snapshots: '@api.global/typedsocket@3.1.1(@push.rocks/smartserve@1.1.2)': dependencies: - '@api.global/typedrequest': 3.1.11 + '@api.global/typedrequest': 3.2.5 '@api.global/typedrequest-interfaces': 3.0.19 '@push.rocks/isohash': 2.0.1 '@push.rocks/smartjson': 5.2.0 @@ -3950,7 +3794,7 @@ snapshots: '@api.global/typedsocket@4.1.0(@push.rocks/smartserve@1.1.2)': dependencies: - '@api.global/typedrequest': 3.1.11 + '@api.global/typedrequest': 3.2.5 '@api.global/typedrequest-interfaces': 3.0.19 '@push.rocks/isohash': 2.0.1 '@push.rocks/smartdelay': 3.0.5 @@ -4008,31 +3852,31 @@ snapshots: '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 - '@aws-sdk/client-s3@3.940.0': + '@aws-sdk/client-s3@3.943.0': dependencies: '@aws-crypto/sha1-browser': 5.2.0 '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.940.0 - '@aws-sdk/credential-provider-node': 3.940.0 + '@aws-sdk/core': 3.943.0 + '@aws-sdk/credential-provider-node': 3.943.0 '@aws-sdk/middleware-bucket-endpoint': 3.936.0 '@aws-sdk/middleware-expect-continue': 3.936.0 - '@aws-sdk/middleware-flexible-checksums': 3.940.0 + '@aws-sdk/middleware-flexible-checksums': 3.943.0 '@aws-sdk/middleware-host-header': 3.936.0 '@aws-sdk/middleware-location-constraint': 3.936.0 '@aws-sdk/middleware-logger': 3.936.0 '@aws-sdk/middleware-recursion-detection': 3.936.0 - '@aws-sdk/middleware-sdk-s3': 3.940.0 + '@aws-sdk/middleware-sdk-s3': 3.943.0 '@aws-sdk/middleware-ssec': 3.936.0 - '@aws-sdk/middleware-user-agent': 3.940.0 + '@aws-sdk/middleware-user-agent': 3.943.0 '@aws-sdk/region-config-resolver': 3.936.0 - '@aws-sdk/signature-v4-multi-region': 3.940.0 + '@aws-sdk/signature-v4-multi-region': 3.943.0 '@aws-sdk/types': 3.936.0 '@aws-sdk/util-endpoints': 3.936.0 '@aws-sdk/util-user-agent-browser': 3.936.0 - '@aws-sdk/util-user-agent-node': 3.940.0 + '@aws-sdk/util-user-agent-node': 3.943.0 '@smithy/config-resolver': 4.4.3 - '@smithy/core': 3.18.5 + '@smithy/core': 3.18.7 '@smithy/eventstream-serde-browser': 4.2.5 '@smithy/eventstream-serde-config-resolver': 4.3.5 '@smithy/eventstream-serde-node': 4.2.5 @@ -4043,21 +3887,21 @@ snapshots: '@smithy/invalid-dependency': 4.2.5 '@smithy/md5-js': 4.2.5 '@smithy/middleware-content-length': 4.2.5 - '@smithy/middleware-endpoint': 4.3.12 - '@smithy/middleware-retry': 4.4.12 + '@smithy/middleware-endpoint': 4.3.14 + '@smithy/middleware-retry': 4.4.14 '@smithy/middleware-serde': 4.2.6 '@smithy/middleware-stack': 4.2.5 '@smithy/node-config-provider': 4.3.5 '@smithy/node-http-handler': 4.4.5 '@smithy/protocol-http': 5.3.5 - '@smithy/smithy-client': 4.9.8 + '@smithy/smithy-client': 4.9.10 '@smithy/types': 4.9.0 '@smithy/url-parser': 4.2.5 '@smithy/util-base64': 4.3.0 '@smithy/util-body-length-browser': 4.2.0 '@smithy/util-body-length-node': 4.2.1 - '@smithy/util-defaults-mode-browser': 4.3.11 - '@smithy/util-defaults-mode-node': 4.2.14 + '@smithy/util-defaults-mode-browser': 4.3.13 + '@smithy/util-defaults-mode-node': 4.2.16 '@smithy/util-endpoints': 3.2.5 '@smithy/util-middleware': 4.2.5 '@smithy/util-retry': 4.2.5 @@ -4068,41 +3912,41 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso@3.940.0': + '@aws-sdk/client-sso@3.943.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.940.0 + '@aws-sdk/core': 3.943.0 '@aws-sdk/middleware-host-header': 3.936.0 '@aws-sdk/middleware-logger': 3.936.0 '@aws-sdk/middleware-recursion-detection': 3.936.0 - '@aws-sdk/middleware-user-agent': 3.940.0 + '@aws-sdk/middleware-user-agent': 3.943.0 '@aws-sdk/region-config-resolver': 3.936.0 '@aws-sdk/types': 3.936.0 '@aws-sdk/util-endpoints': 3.936.0 '@aws-sdk/util-user-agent-browser': 3.936.0 - '@aws-sdk/util-user-agent-node': 3.940.0 + '@aws-sdk/util-user-agent-node': 3.943.0 '@smithy/config-resolver': 4.4.3 - '@smithy/core': 3.18.5 + '@smithy/core': 3.18.7 '@smithy/fetch-http-handler': 5.3.6 '@smithy/hash-node': 4.2.5 '@smithy/invalid-dependency': 4.2.5 '@smithy/middleware-content-length': 4.2.5 - '@smithy/middleware-endpoint': 4.3.12 - '@smithy/middleware-retry': 4.4.12 + '@smithy/middleware-endpoint': 4.3.14 + '@smithy/middleware-retry': 4.4.14 '@smithy/middleware-serde': 4.2.6 '@smithy/middleware-stack': 4.2.5 '@smithy/node-config-provider': 4.3.5 '@smithy/node-http-handler': 4.4.5 '@smithy/protocol-http': 5.3.5 - '@smithy/smithy-client': 4.9.8 + '@smithy/smithy-client': 4.9.10 '@smithy/types': 4.9.0 '@smithy/url-parser': 4.2.5 '@smithy/util-base64': 4.3.0 '@smithy/util-body-length-browser': 4.2.0 '@smithy/util-body-length-node': 4.2.1 - '@smithy/util-defaults-mode-browser': 4.3.11 - '@smithy/util-defaults-mode-node': 4.2.14 + '@smithy/util-defaults-mode-browser': 4.3.13 + '@smithy/util-defaults-mode-node': 4.2.16 '@smithy/util-endpoints': 3.2.5 '@smithy/util-middleware': 4.2.5 '@smithy/util-retry': 4.2.5 @@ -4111,53 +3955,53 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/core@3.940.0': + '@aws-sdk/core@3.943.0': dependencies: '@aws-sdk/types': 3.936.0 '@aws-sdk/xml-builder': 3.930.0 - '@smithy/core': 3.18.5 + '@smithy/core': 3.18.7 '@smithy/node-config-provider': 4.3.5 '@smithy/property-provider': 4.2.5 '@smithy/protocol-http': 5.3.5 '@smithy/signature-v4': 5.3.5 - '@smithy/smithy-client': 4.9.8 + '@smithy/smithy-client': 4.9.10 '@smithy/types': 4.9.0 '@smithy/util-base64': 4.3.0 '@smithy/util-middleware': 4.2.5 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-env@3.940.0': + '@aws-sdk/credential-provider-env@3.943.0': dependencies: - '@aws-sdk/core': 3.940.0 + '@aws-sdk/core': 3.943.0 '@aws-sdk/types': 3.936.0 '@smithy/property-provider': 4.2.5 '@smithy/types': 4.9.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.940.0': + '@aws-sdk/credential-provider-http@3.943.0': dependencies: - '@aws-sdk/core': 3.940.0 + '@aws-sdk/core': 3.943.0 '@aws-sdk/types': 3.936.0 '@smithy/fetch-http-handler': 5.3.6 '@smithy/node-http-handler': 4.4.5 '@smithy/property-provider': 4.2.5 '@smithy/protocol-http': 5.3.5 - '@smithy/smithy-client': 4.9.8 + '@smithy/smithy-client': 4.9.10 '@smithy/types': 4.9.0 '@smithy/util-stream': 4.5.6 tslib: 2.8.1 - '@aws-sdk/credential-provider-ini@3.940.0': + '@aws-sdk/credential-provider-ini@3.943.0': dependencies: - '@aws-sdk/core': 3.940.0 - '@aws-sdk/credential-provider-env': 3.940.0 - '@aws-sdk/credential-provider-http': 3.940.0 - '@aws-sdk/credential-provider-login': 3.940.0 - '@aws-sdk/credential-provider-process': 3.940.0 - '@aws-sdk/credential-provider-sso': 3.940.0 - '@aws-sdk/credential-provider-web-identity': 3.940.0 - '@aws-sdk/nested-clients': 3.940.0 + '@aws-sdk/core': 3.943.0 + '@aws-sdk/credential-provider-env': 3.943.0 + '@aws-sdk/credential-provider-http': 3.943.0 + '@aws-sdk/credential-provider-login': 3.943.0 + '@aws-sdk/credential-provider-process': 3.943.0 + '@aws-sdk/credential-provider-sso': 3.943.0 + '@aws-sdk/credential-provider-web-identity': 3.943.0 + '@aws-sdk/nested-clients': 3.943.0 '@aws-sdk/types': 3.936.0 '@smithy/credential-provider-imds': 4.2.5 '@smithy/property-provider': 4.2.5 @@ -4167,10 +4011,10 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-login@3.940.0': + '@aws-sdk/credential-provider-login@3.943.0': dependencies: - '@aws-sdk/core': 3.940.0 - '@aws-sdk/nested-clients': 3.940.0 + '@aws-sdk/core': 3.943.0 + '@aws-sdk/nested-clients': 3.943.0 '@aws-sdk/types': 3.936.0 '@smithy/property-provider': 4.2.5 '@smithy/protocol-http': 5.3.5 @@ -4180,14 +4024,14 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.940.0': + '@aws-sdk/credential-provider-node@3.943.0': dependencies: - '@aws-sdk/credential-provider-env': 3.940.0 - '@aws-sdk/credential-provider-http': 3.940.0 - '@aws-sdk/credential-provider-ini': 3.940.0 - '@aws-sdk/credential-provider-process': 3.940.0 - '@aws-sdk/credential-provider-sso': 3.940.0 - '@aws-sdk/credential-provider-web-identity': 3.940.0 + '@aws-sdk/credential-provider-env': 3.943.0 + '@aws-sdk/credential-provider-http': 3.943.0 + '@aws-sdk/credential-provider-ini': 3.943.0 + '@aws-sdk/credential-provider-process': 3.943.0 + '@aws-sdk/credential-provider-sso': 3.943.0 + '@aws-sdk/credential-provider-web-identity': 3.943.0 '@aws-sdk/types': 3.936.0 '@smithy/credential-provider-imds': 4.2.5 '@smithy/property-provider': 4.2.5 @@ -4197,20 +4041,20 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-process@3.940.0': + '@aws-sdk/credential-provider-process@3.943.0': dependencies: - '@aws-sdk/core': 3.940.0 + '@aws-sdk/core': 3.943.0 '@aws-sdk/types': 3.936.0 '@smithy/property-provider': 4.2.5 '@smithy/shared-ini-file-loader': 4.4.0 '@smithy/types': 4.9.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.940.0': + '@aws-sdk/credential-provider-sso@3.943.0': dependencies: - '@aws-sdk/client-sso': 3.940.0 - '@aws-sdk/core': 3.940.0 - '@aws-sdk/token-providers': 3.940.0 + '@aws-sdk/client-sso': 3.943.0 + '@aws-sdk/core': 3.943.0 + '@aws-sdk/token-providers': 3.943.0 '@aws-sdk/types': 3.936.0 '@smithy/property-provider': 4.2.5 '@smithy/shared-ini-file-loader': 4.4.0 @@ -4219,10 +4063,10 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-web-identity@3.940.0': + '@aws-sdk/credential-provider-web-identity@3.943.0': dependencies: - '@aws-sdk/core': 3.940.0 - '@aws-sdk/nested-clients': 3.940.0 + '@aws-sdk/core': 3.943.0 + '@aws-sdk/nested-clients': 3.943.0 '@aws-sdk/types': 3.936.0 '@smithy/property-provider': 4.2.5 '@smithy/shared-ini-file-loader': 4.4.0 @@ -4248,12 +4092,12 @@ snapshots: '@smithy/types': 4.9.0 tslib: 2.8.1 - '@aws-sdk/middleware-flexible-checksums@3.940.0': + '@aws-sdk/middleware-flexible-checksums@3.943.0': dependencies: '@aws-crypto/crc32': 5.2.0 '@aws-crypto/crc32c': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/core': 3.940.0 + '@aws-sdk/core': 3.943.0 '@aws-sdk/types': 3.936.0 '@smithy/is-array-buffer': 4.2.0 '@smithy/node-config-provider': 4.3.5 @@ -4286,21 +4130,21 @@ snapshots: '@aws-sdk/middleware-recursion-detection@3.936.0': dependencies: '@aws-sdk/types': 3.936.0 - '@aws/lambda-invoke-store': 0.2.1 + '@aws/lambda-invoke-store': 0.2.2 '@smithy/protocol-http': 5.3.5 '@smithy/types': 4.9.0 tslib: 2.8.1 - '@aws-sdk/middleware-sdk-s3@3.940.0': + '@aws-sdk/middleware-sdk-s3@3.943.0': dependencies: - '@aws-sdk/core': 3.940.0 + '@aws-sdk/core': 3.943.0 '@aws-sdk/types': 3.936.0 '@aws-sdk/util-arn-parser': 3.893.0 - '@smithy/core': 3.18.5 + '@smithy/core': 3.18.7 '@smithy/node-config-provider': 4.3.5 '@smithy/protocol-http': 5.3.5 '@smithy/signature-v4': 5.3.5 - '@smithy/smithy-client': 4.9.8 + '@smithy/smithy-client': 4.9.10 '@smithy/types': 4.9.0 '@smithy/util-config-provider': 4.2.0 '@smithy/util-middleware': 4.2.5 @@ -4314,51 +4158,51 @@ snapshots: '@smithy/types': 4.9.0 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.940.0': + '@aws-sdk/middleware-user-agent@3.943.0': dependencies: - '@aws-sdk/core': 3.940.0 + '@aws-sdk/core': 3.943.0 '@aws-sdk/types': 3.936.0 '@aws-sdk/util-endpoints': 3.936.0 - '@smithy/core': 3.18.5 + '@smithy/core': 3.18.7 '@smithy/protocol-http': 5.3.5 '@smithy/types': 4.9.0 tslib: 2.8.1 - '@aws-sdk/nested-clients@3.940.0': + '@aws-sdk/nested-clients@3.943.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.940.0 + '@aws-sdk/core': 3.943.0 '@aws-sdk/middleware-host-header': 3.936.0 '@aws-sdk/middleware-logger': 3.936.0 '@aws-sdk/middleware-recursion-detection': 3.936.0 - '@aws-sdk/middleware-user-agent': 3.940.0 + '@aws-sdk/middleware-user-agent': 3.943.0 '@aws-sdk/region-config-resolver': 3.936.0 '@aws-sdk/types': 3.936.0 '@aws-sdk/util-endpoints': 3.936.0 '@aws-sdk/util-user-agent-browser': 3.936.0 - '@aws-sdk/util-user-agent-node': 3.940.0 + '@aws-sdk/util-user-agent-node': 3.943.0 '@smithy/config-resolver': 4.4.3 - '@smithy/core': 3.18.5 + '@smithy/core': 3.18.7 '@smithy/fetch-http-handler': 5.3.6 '@smithy/hash-node': 4.2.5 '@smithy/invalid-dependency': 4.2.5 '@smithy/middleware-content-length': 4.2.5 - '@smithy/middleware-endpoint': 4.3.12 - '@smithy/middleware-retry': 4.4.12 + '@smithy/middleware-endpoint': 4.3.14 + '@smithy/middleware-retry': 4.4.14 '@smithy/middleware-serde': 4.2.6 '@smithy/middleware-stack': 4.2.5 '@smithy/node-config-provider': 4.3.5 '@smithy/node-http-handler': 4.4.5 '@smithy/protocol-http': 5.3.5 - '@smithy/smithy-client': 4.9.8 + '@smithy/smithy-client': 4.9.10 '@smithy/types': 4.9.0 '@smithy/url-parser': 4.2.5 '@smithy/util-base64': 4.3.0 '@smithy/util-body-length-browser': 4.2.0 '@smithy/util-body-length-node': 4.2.1 - '@smithy/util-defaults-mode-browser': 4.3.11 - '@smithy/util-defaults-mode-node': 4.2.14 + '@smithy/util-defaults-mode-browser': 4.3.13 + '@smithy/util-defaults-mode-node': 4.2.16 '@smithy/util-endpoints': 3.2.5 '@smithy/util-middleware': 4.2.5 '@smithy/util-retry': 4.2.5 @@ -4375,19 +4219,19 @@ snapshots: '@smithy/types': 4.9.0 tslib: 2.8.1 - '@aws-sdk/signature-v4-multi-region@3.940.0': + '@aws-sdk/signature-v4-multi-region@3.943.0': dependencies: - '@aws-sdk/middleware-sdk-s3': 3.940.0 + '@aws-sdk/middleware-sdk-s3': 3.943.0 '@aws-sdk/types': 3.936.0 '@smithy/protocol-http': 5.3.5 '@smithy/signature-v4': 5.3.5 '@smithy/types': 4.9.0 tslib: 2.8.1 - '@aws-sdk/token-providers@3.940.0': + '@aws-sdk/token-providers@3.943.0': dependencies: - '@aws-sdk/core': 3.940.0 - '@aws-sdk/nested-clients': 3.940.0 + '@aws-sdk/core': 3.943.0 + '@aws-sdk/nested-clients': 3.943.0 '@aws-sdk/types': 3.936.0 '@smithy/property-provider': 4.2.5 '@smithy/shared-ini-file-loader': 4.4.0 @@ -4424,9 +4268,9 @@ snapshots: bowser: 2.13.1 tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.940.0': + '@aws-sdk/util-user-agent-node@3.943.0': dependencies: - '@aws-sdk/middleware-user-agent': 3.940.0 + '@aws-sdk/middleware-user-agent': 3.943.0 '@aws-sdk/types': 3.936.0 '@smithy/node-config-provider': 4.3.5 '@smithy/types': 4.9.0 @@ -4438,7 +4282,7 @@ snapshots: fast-xml-parser: 5.2.5 tslib: 2.8.1 - '@aws/lambda-invoke-store@0.2.1': {} + '@aws/lambda-invoke-store@0.2.2': {} '@babel/runtime@7.28.4': {} @@ -4446,6 +4290,8 @@ snapshots: '@cloudflare/workers-types@4.20251202.0': {} + '@cloudflare/workers-types@4.20251205.0': {} + '@configvault.io/interfaces@1.0.17': dependencies: '@api.global/typedrequest-interfaces': 3.0.19 @@ -4468,7 +4314,7 @@ snapshots: '@consent.software/webclient@1.1.0': dependencies: - '@api.global/typedrequest': 3.1.11 + '@api.global/typedrequest': 3.2.5 '@consent.software/interfaces': 1.0.14 '@push.rocks/smarttime': 4.1.1 '@push.rocks/webstore': 2.0.20 @@ -4511,14 +4357,21 @@ snapshots: '@design.estate/dees-comms@1.0.27': dependencies: - '@api.global/typedrequest': 3.1.11 + '@api.global/typedrequest': 3.2.5 + '@api.global/typedrequest-interfaces': 3.0.19 + '@push.rocks/smartdelay': 3.0.5 + broadcast-channel: 7.2.0 + + '@design.estate/dees-comms@1.0.30': + dependencies: + '@api.global/typedrequest': 3.2.5 '@api.global/typedrequest-interfaces': 3.0.19 '@push.rocks/smartdelay': 3.0.5 broadcast-channel: 7.2.0 '@design.estate/dees-domtools@2.3.6': dependencies: - '@api.global/typedrequest': 3.1.11 + '@api.global/typedrequest': 3.2.5 '@design.estate/dees-comms': 1.0.27 '@push.rocks/lik': 6.2.2 '@push.rocks/smartdelay': 3.0.5 @@ -4582,159 +4435,81 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.25.12': - optional: true - '@esbuild/aix-ppc64@0.27.1': optional: true - '@esbuild/android-arm64@0.25.12': - optional: true - '@esbuild/android-arm64@0.27.1': optional: true - '@esbuild/android-arm@0.25.12': - optional: true - '@esbuild/android-arm@0.27.1': optional: true - '@esbuild/android-x64@0.25.12': - optional: true - '@esbuild/android-x64@0.27.1': optional: true - '@esbuild/darwin-arm64@0.25.12': - optional: true - '@esbuild/darwin-arm64@0.27.1': optional: true - '@esbuild/darwin-x64@0.25.12': - optional: true - '@esbuild/darwin-x64@0.27.1': optional: true - '@esbuild/freebsd-arm64@0.25.12': - optional: true - '@esbuild/freebsd-arm64@0.27.1': optional: true - '@esbuild/freebsd-x64@0.25.12': - optional: true - '@esbuild/freebsd-x64@0.27.1': optional: true - '@esbuild/linux-arm64@0.25.12': - optional: true - '@esbuild/linux-arm64@0.27.1': optional: true - '@esbuild/linux-arm@0.25.12': - optional: true - '@esbuild/linux-arm@0.27.1': optional: true - '@esbuild/linux-ia32@0.25.12': - optional: true - '@esbuild/linux-ia32@0.27.1': optional: true - '@esbuild/linux-loong64@0.25.12': - optional: true - '@esbuild/linux-loong64@0.27.1': optional: true - '@esbuild/linux-mips64el@0.25.12': - optional: true - '@esbuild/linux-mips64el@0.27.1': optional: true - '@esbuild/linux-ppc64@0.25.12': - optional: true - '@esbuild/linux-ppc64@0.27.1': optional: true - '@esbuild/linux-riscv64@0.25.12': - optional: true - '@esbuild/linux-riscv64@0.27.1': optional: true - '@esbuild/linux-s390x@0.25.12': - optional: true - '@esbuild/linux-s390x@0.27.1': optional: true - '@esbuild/linux-x64@0.25.12': - optional: true - '@esbuild/linux-x64@0.27.1': optional: true - '@esbuild/netbsd-arm64@0.25.12': - optional: true - '@esbuild/netbsd-arm64@0.27.1': optional: true - '@esbuild/netbsd-x64@0.25.12': - optional: true - '@esbuild/netbsd-x64@0.27.1': optional: true - '@esbuild/openbsd-arm64@0.25.12': - optional: true - '@esbuild/openbsd-arm64@0.27.1': optional: true - '@esbuild/openbsd-x64@0.25.12': - optional: true - '@esbuild/openbsd-x64@0.27.1': optional: true - '@esbuild/openharmony-arm64@0.25.12': - optional: true - '@esbuild/openharmony-arm64@0.27.1': optional: true - '@esbuild/sunos-x64@0.25.12': - optional: true - '@esbuild/sunos-x64@0.27.1': optional: true - '@esbuild/win32-arm64@0.25.12': - optional: true - '@esbuild/win32-arm64@0.27.1': optional: true - '@esbuild/win32-ia32@0.25.12': - optional: true - '@esbuild/win32-ia32@0.27.1': optional: true - '@esbuild/win32-x64@0.25.12': - optional: true - '@esbuild/win32-x64@0.27.1': optional: true @@ -4821,7 +4596,7 @@ snapshots: dependencies: '@push.rocks/smartfile': 11.2.7 '@push.rocks/smartshell': 3.3.0 - tsx: 4.20.6 + tsx: 4.21.0 '@git.zone/tswatch@2.2.3(@push.rocks/smartserve@1.1.2)': dependencies: @@ -5147,7 +4922,7 @@ snapshots: '@push.rocks/qenv@6.1.3': dependencies: - '@api.global/typedrequest': 3.1.11 + '@api.global/typedrequest': 3.2.5 '@configvault.io/interfaces': 1.0.17 '@push.rocks/smartfile': 11.2.7 '@push.rocks/smartlog': 3.1.10 @@ -5175,7 +4950,7 @@ snapshots: '@push.rocks/smartbucket@3.3.10': dependencies: - '@aws-sdk/client-s3': 3.940.0 + '@aws-sdk/client-s3': 3.943.0 '@push.rocks/smartmime': 2.0.4 '@push.rocks/smartpath': 6.0.0 '@push.rocks/smartpromise': 4.2.3 @@ -5229,7 +5004,7 @@ snapshots: dependencies: '@push.rocks/smartpromise': 4.2.3 '@types/node-forge': 1.3.14 - node-forge: 1.3.2 + node-forge: 1.3.3 '@push.rocks/smartdata@5.16.7': dependencies: @@ -5378,7 +5153,7 @@ snapshots: '@push.rocks/lik': 6.2.2 '@push.rocks/smartdelay': 3.0.5 '@push.rocks/smartfile-interfaces': 1.0.7 - '@push.rocks/smartfs': 1.1.2 + '@push.rocks/smartfs': 1.2.0 '@push.rocks/smarthash': 3.2.6 '@push.rocks/smartjson': 5.2.0 '@push.rocks/smartmime': 2.0.4 @@ -5390,10 +5165,6 @@ snapshots: glob: 11.1.0 js-yaml: 4.1.1 - '@push.rocks/smartfs@1.1.2': - dependencies: - '@push.rocks/smartpath': 6.0.0 - '@push.rocks/smartfs@1.2.0': dependencies: '@push.rocks/smartpath': 6.0.0 @@ -5427,7 +5198,7 @@ snapshots: '@push.rocks/smartjson': 5.2.0 '@tsclass/tsclass': 4.4.4 '@types/jsonwebtoken': 9.0.10 - jsonwebtoken: 9.0.2 + jsonwebtoken: 9.0.3 '@push.rocks/smartlog-destination-devtools@1.0.12': dependencies: @@ -5505,7 +5276,7 @@ snapshots: '@push.rocks/smartdata': 5.16.7 '@push.rocks/smartpath': 5.1.0 '@push.rocks/smartpromise': 4.2.3 - mongodb-memory-server: 10.3.0 + mongodb-memory-server: 10.4.1 transitivePeerDependencies: - '@aws-sdk/credential-providers' - '@mongodb-js/zstd' @@ -5611,7 +5382,7 @@ snapshots: '@push.rocks/smartserve@1.1.2': dependencies: - '@api.global/typedrequest': 3.1.11 + '@api.global/typedrequest': 3.2.5 '@push.rocks/lik': 6.2.2 '@push.rocks/smartenv': 6.0.0 '@push.rocks/smartlog': 3.1.10 @@ -5958,7 +5729,7 @@ snapshots: '@serve.zone/platformclient@1.1.2(@push.rocks/smartserve@1.1.2)': dependencies: - '@api.global/typedrequest': 3.1.11 + '@api.global/typedrequest': 3.2.5 '@api.global/typedserver': 3.0.80(@push.rocks/smartserve@1.1.2) '@api.global/typedsocket': 3.1.1(@push.rocks/smartserve@1.1.2) '@push.rocks/qenv': 6.1.3 @@ -5999,7 +5770,7 @@ snapshots: '@smithy/util-middleware': 4.2.5 tslib: 2.8.1 - '@smithy/core@3.18.5': + '@smithy/core@3.18.7': dependencies: '@smithy/middleware-serde': 4.2.6 '@smithy/protocol-http': 5.3.5 @@ -6103,9 +5874,9 @@ snapshots: '@smithy/types': 4.9.0 tslib: 2.8.1 - '@smithy/middleware-endpoint@4.3.12': + '@smithy/middleware-endpoint@4.3.14': dependencies: - '@smithy/core': 3.18.5 + '@smithy/core': 3.18.7 '@smithy/middleware-serde': 4.2.6 '@smithy/node-config-provider': 4.3.5 '@smithy/shared-ini-file-loader': 4.4.0 @@ -6114,12 +5885,12 @@ snapshots: '@smithy/util-middleware': 4.2.5 tslib: 2.8.1 - '@smithy/middleware-retry@4.4.12': + '@smithy/middleware-retry@4.4.14': dependencies: '@smithy/node-config-provider': 4.3.5 '@smithy/protocol-http': 5.3.5 '@smithy/service-error-classification': 4.2.5 - '@smithy/smithy-client': 4.9.8 + '@smithy/smithy-client': 4.9.10 '@smithy/types': 4.9.0 '@smithy/util-middleware': 4.2.5 '@smithy/util-retry': 4.2.5 @@ -6193,10 +5964,10 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 - '@smithy/smithy-client@4.9.8': + '@smithy/smithy-client@4.9.10': dependencies: - '@smithy/core': 3.18.5 - '@smithy/middleware-endpoint': 4.3.12 + '@smithy/core': 3.18.7 + '@smithy/middleware-endpoint': 4.3.14 '@smithy/middleware-stack': 4.2.5 '@smithy/protocol-http': 5.3.5 '@smithy/types': 4.9.0 @@ -6241,20 +6012,20 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/util-defaults-mode-browser@4.3.11': + '@smithy/util-defaults-mode-browser@4.3.13': dependencies: '@smithy/property-provider': 4.2.5 - '@smithy/smithy-client': 4.9.8 + '@smithy/smithy-client': 4.9.10 '@smithy/types': 4.9.0 tslib: 2.8.1 - '@smithy/util-defaults-mode-node@4.2.14': + '@smithy/util-defaults-mode-node@4.2.16': dependencies: '@smithy/config-resolver': 4.4.3 '@smithy/credential-provider-imds': 4.2.5 '@smithy/node-config-provider': 4.3.5 '@smithy/property-provider': 4.2.5 - '@smithy/smithy-client': 4.9.8 + '@smithy/smithy-client': 4.9.10 '@smithy/types': 4.9.0 tslib: 2.8.1 @@ -6716,7 +6487,7 @@ snapshots: asn1js: 3.0.6 axios: 1.13.2(debug@4.4.3) debug: 4.4.3 - node-forge: 1.3.2 + node-forge: 1.3.3 transitivePeerDependencies: - supports-color @@ -7075,35 +6846,6 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 - esbuild@0.25.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - esbuild@0.27.1: optionalDependencies: '@esbuild/aix-ppc64': 0.27.1 @@ -7567,9 +7309,9 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 - jsonwebtoken@9.0.2: + jsonwebtoken@9.0.3: dependencies: - jws: 3.2.2 + jws: 4.0.1 lodash.includes: 4.3.0 lodash.isboolean: 3.0.3 lodash.isinteger: 4.0.4 @@ -7580,15 +7322,15 @@ snapshots: ms: 2.1.3 semver: 7.7.3 - jwa@1.4.2: + jwa@2.0.1: dependencies: buffer-equal-constant-time: 1.0.1 ecdsa-sig-formatter: 1.0.11 safe-buffer: 5.2.1 - jws@3.2.2: + jws@4.0.1: dependencies: - jwa: 1.4.2 + jwa: 2.0.1 safe-buffer: 5.2.1 keyv@4.5.4: @@ -7686,7 +7428,7 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.2.2: {} + lru-cache@11.2.4: {} lucide@0.555.0: {} @@ -8100,7 +7842,7 @@ snapshots: '@types/whatwg-url': 13.0.0 whatwg-url: 14.2.0 - mongodb-memory-server-core@10.3.0: + mongodb-memory-server-core@10.4.1: dependencies: async-mutex: 0.5.0 camelcase: 6.3.0 @@ -8126,9 +7868,9 @@ snapshots: - socks - supports-color - mongodb-memory-server@10.3.0: + mongodb-memory-server@10.4.1: dependencies: - mongodb-memory-server-core: 10.3.0 + mongodb-memory-server-core: 10.4.1 tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/credential-providers' @@ -8174,7 +7916,7 @@ snapshots: dependencies: lower-case: 1.1.4 - node-forge@1.3.2: {} + node-forge@1.3.3: {} normalize-newline@4.1.0: dependencies: @@ -8261,7 +8003,7 @@ snapshots: path-scurry@2.0.1: dependencies: - lru-cache: 11.2.2 + lru-cache: 11.2.4 minipass: 7.1.2 path-to-regexp@8.3.0: {} @@ -8828,9 +8570,9 @@ snapshots: tslib@2.8.1: {} - tsx@4.20.6: + tsx@4.21.0: dependencies: - esbuild: 0.25.12 + esbuild: 0.27.1 get-tsconfig: 4.13.0 optionalDependencies: fsevents: 2.3.3 diff --git a/stories/README.md b/stories/README.md index 2aab3df..ef4b673 100644 --- a/stories/README.md +++ b/stories/README.md @@ -30,7 +30,7 @@ stories/ | ID | Title | Priority | Source | |----|-------|----------|--------| | ORG-001 | [Sync Billing Plans with Users](organization-owner/ORG-001-billing-sync.md) | High | TODO | -| ORG-002 | [Invite and Manage Team Members](organization-owner/ORG-002-member-management.md) | Critical | New | +| ORG-002 | [Invite and Manage Team Members](organization-owner/ORG-002-member-management.md) | Critical | Complete | | ORG-003 | [Assign Roles to Members](organization-owner/ORG-003-role-assignment.md) | High | Partial | | ORG-004 | [Customize Organization Branding](organization-owner/ORG-004-org-branding.md) | Medium | New | | ORG-005 | [View Organization Usage Analytics](organization-owner/ORG-005-usage-analytics.md) | Medium | New | @@ -69,7 +69,7 @@ stories/ | Priority | Count | Stories | |----------|-------|---------| -| Critical | 3 | EU-002, ORG-002, ADM-001 | +| Critical | 2 | EU-002, ADM-001 | | High | 12 | EU-001, EU-004, ORG-001, ORG-003, ORG-006, ORG-009, DEV-001, DEV-002, DEV-004, ADM-002, ADM-003, ADM-008 | | Medium | 14 | EU-003, EU-005, EU-006, ORG-004, ORG-005, ORG-007, ORG-008, ORG-010, ORG-011, DEV-003, DEV-005, DEV-007, ADM-004, ADM-005, ADM-007 | | Low | 6 | EU-007, EU-008, DEV-006, DEV-008, ADM-006 | diff --git a/stories/organization-owner/ORG-002-member-management.md b/stories/organization-owner/ORG-002-member-management.md index 86062d9..ab14c23 100644 --- a/stories/organization-owner/ORG-002-member-management.md +++ b/stories/organization-owner/ORG-002-member-management.md @@ -2,7 +2,7 @@ **ID:** ORG-002 **Priority:** Critical -**Status:** In Development +**Status:** Complete ## User Story As an organization owner, I want to invite team members to my organization and manage their access so that my team can collaborate securely. @@ -14,8 +14,8 @@ As an organization owner, I want to invite team members to my organization and m - [x] Owner can view pending invitations and resend/cancel them - [x] Owner can see all current members with their roles - [x] Owner can remove members from organization -- [ ] Owner can transfer ownership to another member -- [ ] Bulk invite via CSV upload +- [x] Owner can transfer ownership to another member +- [x] Bulk invite via CSV upload ## Technical Implementation diff --git a/ts/reception/classes.organizationmanager.ts b/ts/reception/classes.organizationmanager.ts index 5f857bc..797f29f 100644 --- a/ts/reception/classes.organizationmanager.ts +++ b/ts/reception/classes.organizationmanager.ts @@ -50,13 +50,14 @@ export class OrganizationManager { action: 'create', organizationId: newOrg.id, userId: userData.id, - role: 'admin', + roles: ['owner'], }); newOrg.data.roleIds.push(role.id); await newOrg.save(); return { nameAvailable: true, - resultingOrganization: await newOrg.createSavableObject() + resultingOrganization: await newOrg.createSavableObject(), + role: await role.createSavableObject(), } break; } diff --git a/ts/reception/classes.userinvitationmanager.ts b/ts/reception/classes.userinvitationmanager.ts index badf759..e2dfea9 100644 --- a/ts/reception/classes.userinvitationmanager.ts +++ b/ts/reception/classes.userinvitationmanager.ts @@ -456,6 +456,159 @@ export class UserInvitationManager { } ) ); + + // Bulk create invitations + this.typedrouter.addTypedHandler( + new plugins.typedrequest.TypedHandler( + 'bulkCreateInvitations', + async (requestArg) => { + const user = await this.receptionRef.userManager.getUserByJwtValidation(requestArg.jwt); + await this.verifyUserIsAdminOfOrg(user.id, requestArg.organizationId); + + const org = await this.receptionRef.organizationmanager.COrganization.getInstance({ + id: requestArg.organizationId, + }); + const orgName = org?.data.name || 'an organization'; + + const results: Array<{ + email: string; + success: boolean; + status: 'invited' | 'already_member' | 'invalid_email' | 'error'; + message?: string; + }> = []; + const summary = { + total: 0, + invited: 0, + alreadyMembers: 0, + invalid: 0, + errors: 0, + }; + + // Deduplicate emails in the batch + const processedEmails = new Set(); + + for (const inv of requestArg.invitations) { + summary.total++; + const email = inv.email?.toLowerCase().trim(); + + // Validate email format + if (!email || !this.isValidEmail(email)) { + results.push({ + email: inv.email || '', + success: false, + status: 'invalid_email', + message: 'Invalid email format', + }); + summary.invalid++; + continue; + } + + // Skip duplicates within batch + if (processedEmails.has(email)) { + results.push({ + email, + success: false, + status: 'invalid_email', + message: 'Duplicate email in batch', + }); + summary.invalid++; + continue; + } + processedEmails.add(email); + + try { + // Check if user with this email already exists + const existingUser = await this.receptionRef.userManager.CUser.getInstance({ + data: { email }, + }); + + if (existingUser) { + // Check if already a member + const existingRole = await this.receptionRef.roleManager.CRole.getInstance({ + data: { + userId: existingUser.id, + organizationId: requestArg.organizationId, + }, + }); + + if (existingRole) { + results.push({ + email, + success: false, + status: 'already_member', + message: 'Already a member of this organization', + }); + summary.alreadyMembers++; + continue; + } + + // Add existing user to org + const roles = inv.roles?.length ? inv.roles : requestArg.defaultRoles; + await this.receptionRef.roleManager.modifyRoleForUserAtOrg({ + action: 'create', + userId: existingUser.id, + organizationId: requestArg.organizationId, + roles, + }); + results.push({ + email, + success: true, + status: 'invited', + message: 'Existing user added to organization', + }); + summary.invited++; + continue; + } + + // Check if invitation already exists + let invitation = await this.CUserInvitation.getInstance({ + data: { email }, + }); + + const roles = inv.roles?.length ? inv.roles : requestArg.defaultRoles; + + if (invitation) { + // Add org to existing invitation + await invitation.addOrganization(requestArg.organizationId, user.id, roles); + } else { + // Create new invitation + invitation = await UserInvitation.createNewInvitation( + email, + requestArg.organizationId, + user.id, + roles + ); + } + + // Send invitation email + await this.receptionRef.receptionMailer.sendInvitationEmail( + email, + orgName, + invitation.data.token, + this.receptionRef.options.baseUrl + ); + + results.push({ + email, + success: true, + status: 'invited', + }); + summary.invited++; + } catch (error: any) { + results.push({ + email, + success: false, + status: 'error', + message: error.message || 'Unknown error', + }); + summary.errors++; + } + } + + return { success: true, results, summary }; + } + ) + ); } /** @@ -553,4 +706,12 @@ export class UserInvitationManager { throw new plugins.typedrequest.TypedResponseError('Not a member of this organization.'); } } + + /** + * Validate email format + */ + private isValidEmail(email: string): boolean { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailRegex.test(email); + } } diff --git a/ts_interfaces/request/loint-reception.userinvitation.ts b/ts_interfaces/request/loint-reception.userinvitation.ts index 536eafb..1ee7047 100644 --- a/ts_interfaces/request/loint-reception.userinvitation.ts +++ b/ts_interfaces/request/loint-reception.userinvitation.ts @@ -209,3 +209,39 @@ export interface IReq_GetInvitationByToken requiresRegistration: boolean; }; } + +/** + * Bulk create invitations from a list (typically from CSV import) + */ +export interface IReq_BulkCreateInvitations + extends plugins.typedRequestInterfaces.implementsTR< + plugins.typedRequestInterfaces.ITypedRequest, + IReq_BulkCreateInvitations + > { + method: 'bulkCreateInvitations'; + request: { + jwt: string; + organizationId: string; + invitations: Array<{ + email: string; + roles?: string[]; + }>; + defaultRoles: string[]; + }; + response: { + success: boolean; + results: Array<{ + email: string; + success: boolean; + status: 'invited' | 'already_member' | 'invalid_email' | 'error'; + message?: string; + }>; + summary: { + total: number; + invited: number; + alreadyMembers: number; + invalid: number; + errors: number; + }; + }; +} diff --git a/ts_web/elements/account/bulk-invite-modal.ts b/ts_web/elements/account/bulk-invite-modal.ts new file mode 100644 index 0000000..f61a614 --- /dev/null +++ b/ts_web/elements/account/bulk-invite-modal.ts @@ -0,0 +1,585 @@ +import * as plugins from '../../plugins.js'; +import { + customElement, + DeesElement, + html, + css, + cssManager, + state, + type TemplateResult, +} from '@design.estate/dees-element'; + +import { accountDesignTokens } from './sharedstyles.js'; +import { IdpState } from '../../states/idp.state.js'; + +interface IParsedEmail { + email: string; + valid: boolean; + error?: string; +} + +interface IBulkInviteResult { + invitedCount: number; + failedCount: number; + alreadyMemberCount: number; +} + +// Internal form element for reactive state management +@customElement('idp-bulk-invite-form') +export class BulkInviteForm extends DeesElement { + @state() + accessor organizationId: string = ''; + + @state() + accessor organizationName: string = ''; + + @state() + accessor parsedEmails: IParsedEmail[] = []; + + @state() + accessor selectedRoles: string[] = ['viewer']; + + @state() + accessor submitting: boolean = false; + + @state() + accessor error: string = ''; + + @state() + accessor results: IBulkInviteResult | null = null; + + private static readonly AVAILABLE_ROLES = ['admin', 'editor', 'viewer', 'guest']; + + public resolveWith: ((result: IBulkInviteResult | null) => void) | null = null; + public modal: plugins.deesCatalog.DeesModal | null = null; + + public static styles = [ + cssManager.defaultStyles, + accountDesignTokens, + css` + :host { + display: block; + } + + .description { + color: var(--muted-foreground); + font-size: 14px; + margin-bottom: 20px; + } + + .file-upload-area { + border: 2px dashed var(--border); + border-radius: 12px; + padding: 32px; + text-align: center; + cursor: pointer; + transition: all 0.15s ease; + margin-bottom: 20px; + } + + .file-upload-area:hover { + border-color: var(--muted-foreground); + background: var(--muted); + } + + .file-upload-area.has-data { + border-style: solid; + border-color: #22c55e; + background: rgba(34, 197, 94, 0.05); + } + + .upload-icon { + font-size: 32px; + color: var(--muted-foreground); + margin-bottom: 12px; + } + + .upload-text { + font-size: 14px; + color: var(--foreground); + margin-bottom: 4px; + } + + .upload-hint { + font-size: 12px; + color: var(--muted-foreground); + } + + .sample-link { + color: #3b82f6; + cursor: pointer; + text-decoration: underline; + } + + input[type="file"] { + display: none; + } + + .preview-section { + margin-bottom: 20px; + } + + .preview-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 12px; + } + + .preview-title { + font-size: 13px; + font-weight: 600; + color: var(--foreground); + } + + .preview-stats { + font-size: 12px; + color: var(--muted-foreground); + } + + .preview-stats .valid { + color: #22c55e; + } + + .preview-stats .invalid { + color: #ef4444; + } + + .preview-list { + max-height: 200px; + overflow-y: auto; + border: 1px solid var(--border); + border-radius: 8px; + } + + .preview-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 14px; + border-bottom: 1px solid var(--border); + font-size: 13px; + } + + .preview-item:last-child { + border-bottom: none; + } + + .preview-item.invalid { + background: rgba(239, 68, 68, 0.05); + } + + .preview-email { + color: var(--foreground); + } + + .preview-status { + font-size: 11px; + padding: 2px 8px; + border-radius: 4px; + } + + .preview-status.valid { + background: rgba(34, 197, 94, 0.2); + color: #22c55e; + } + + .preview-status.invalid { + background: rgba(239, 68, 68, 0.2); + color: #ef4444; + } + + .role-section { + margin-bottom: 20px; + } + + .section-label { + font-size: 13px; + font-weight: 500; + color: var(--foreground); + margin-bottom: 10px; + } + + .role-selector { + display: flex; + flex-wrap: wrap; + gap: 8px; + } + + .role-option { + padding: 8px 16px; + border-radius: 8px; + font-size: 13px; + font-weight: 500; + border: 1px solid var(--border); + background: transparent; + color: var(--muted-foreground); + cursor: pointer; + transition: all 0.15s ease; + } + + .role-option:hover { + border-color: var(--foreground); + color: var(--foreground); + } + + .role-option.selected { + border-color: #3b82f6; + background: rgba(59, 130, 246, 0.1); + color: #3b82f6; + } + + .error-message { + padding: 12px 16px; + background: rgba(239, 68, 68, 0.1); + border: 1px solid rgba(239, 68, 68, 0.3); + border-radius: 8px; + color: #ef4444; + font-size: 13px; + margin-bottom: 16px; + } + + .results-section { + padding: 16px; + background: rgba(34, 197, 94, 0.1); + border: 1px solid rgba(34, 197, 94, 0.3); + border-radius: 8px; + margin-bottom: 16px; + } + + .results-section.has-failures { + background: rgba(234, 179, 8, 0.1); + border-color: rgba(234, 179, 8, 0.3); + } + + .results-title { + font-weight: 600; + margin-bottom: 8px; + color: var(--foreground); + } + + .results-stats { + font-size: 13px; + color: var(--muted-foreground); + } + + .clear-button { + font-size: 12px; + color: #ef4444; + background: none; + border: none; + cursor: pointer; + padding: 4px 8px; + } + + .clear-button:hover { + text-decoration: underline; + } + `, + ]; + + public render(): TemplateResult { + if (this.results) { + return this.renderResults(); + } + + return html` +
+ Upload a CSV file with email addresses to invite multiple people at once. +
+ + ${this.error ? html` +
${this.error}
+ ` : ''} + + ${this.renderFileUpload()} + ${this.parsedEmails.length > 0 ? this.renderPreview() : ''} + ${this.parsedEmails.length > 0 ? this.renderRoleSelector() : ''} + `; + } + + private renderFileUpload(): TemplateResult { + const validCount = this.parsedEmails.filter(e => e.valid).length; + const hasData = this.parsedEmails.length > 0; + + return html` +
this.triggerFileInput()} + @dragover=${(e: DragEvent) => { e.preventDefault(); }} + @drop=${(e: DragEvent) => this.handleFileDrop(e)} + > + this.handleFileSelect(e)} + /> + ${hasData ? html` +
+ +
+
${validCount} valid email(s) loaded
+
Click to replace with a different file
+ ` : html` +
+ +
+
Drop CSV file here or click to browse
+
+ { e.stopPropagation(); this.downloadSampleCSV(); }}>Download sample CSV +
+ `} +
+ `; + } + + private renderPreview(): TemplateResult { + const validCount = this.parsedEmails.filter(e => e.valid).length; + const invalidCount = this.parsedEmails.filter(e => !e.valid).length; + + return html` +
+
+ Email Preview + + ${validCount} valid + ${invalidCount > 0 ? html`, ${invalidCount} invalid` : ''} + + +
+
+ ${this.parsedEmails.map(item => html` +
+ ${item.email} + + ${item.valid ? 'Valid' : (item.error || 'Invalid')} + +
+ `)} +
+
+ `; + } + + private renderRoleSelector(): TemplateResult { + return html` +
+ +
+ ${BulkInviteForm.AVAILABLE_ROLES.map(role => html` + + `)} +
+
+ `; + } + + private renderResults(): TemplateResult { + const hasFailures = this.results!.failedCount > 0 || this.results!.alreadyMemberCount > 0; + + return html` +
+
Bulk Invite Complete
+
+ ${this.results!.invitedCount} invitation(s) sent successfully. + ${this.results!.alreadyMemberCount > 0 ? html`
${this.results!.alreadyMemberCount} already member(s).` : ''} + ${this.results!.failedCount > 0 ? html`
${this.results!.failedCount} failed.` : ''} +
+
+ `; + } + + private triggerFileInput(): void { + const input = this.shadowRoot?.querySelector('input[type="file"]') as HTMLInputElement; + input?.click(); + } + + private handleFileDrop(e: DragEvent): void { + e.preventDefault(); + const file = e.dataTransfer?.files[0]; + if (file) { + this.parseCSVFile(file); + } + } + + private handleFileSelect(e: Event): void { + const input = e.target as HTMLInputElement; + const file = input.files?.[0]; + if (file) { + this.parseCSVFile(file); + } + } + + private async parseCSVFile(file: File): Promise { + const text = await file.text(); + const lines = text.split(/\r?\n/).filter(line => line.trim()); + + const parsed: IParsedEmail[] = []; + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + const seen = new Set(); + + for (let i = 0; i < lines.length; i++) { + const line = lines[i].trim(); + + // Skip header row if it looks like "email" or similar + if (i === 0 && (line.toLowerCase() === 'email' || line.toLowerCase() === 'emails' || line.toLowerCase() === 'e-mail')) { + continue; + } + + // Extract email from line (handle quoted values, commas) + const email = line.replace(/["']/g, '').split(',')[0].trim().toLowerCase(); + + if (!email) { + continue; + } + + if (seen.has(email)) { + parsed.push({ email, valid: false, error: 'Duplicate' }); + continue; + } + seen.add(email); + + if (!emailRegex.test(email)) { + parsed.push({ email, valid: false, error: 'Invalid format' }); + continue; + } + + parsed.push({ email, valid: true }); + } + + this.parsedEmails = parsed; + this.error = ''; + } + + private downloadSampleCSV(): void { + const content = 'email\nuser1@example.com\nuser2@example.com\nuser3@example.com'; + const blob = new Blob([content], { type: 'text/csv' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'sample-invite-list.csv'; + a.click(); + URL.revokeObjectURL(url); + } + + private clearEmails(): void { + this.parsedEmails = []; + this.error = ''; + } + + private toggleRole(role: string): void { + if (this.selectedRoles.includes(role)) { + this.selectedRoles = this.selectedRoles.filter(r => r !== role); + } else { + this.selectedRoles = [...this.selectedRoles, role]; + } + if (this.selectedRoles.length === 0) { + this.selectedRoles = ['viewer']; + } + } + + public canSubmit(): boolean { + const validEmails = this.parsedEmails.filter(e => e.valid); + return validEmails.length > 0 && this.selectedRoles.length > 0 && !this.submitting && !this.results; + } + + public async handleSubmit(): Promise { + if (!this.canSubmit()) { + return null; + } + + this.submitting = true; + this.error = ''; + + try { + const idpState = await IdpState.getSingletonInstance(); + const jwt = await idpState.idpClient.getJwt(); + + const validEmails = this.parsedEmails.filter(e => e.valid); + + const request = idpState.idpClient.typedsocket.createTypedRequest( + 'bulkCreateInvitations' + ); + + const response = await request.fire({ + jwt, + organizationId: this.organizationId, + invitations: validEmails.map(e => ({ email: e.email })), + defaultRoles: this.selectedRoles, + }); + + this.results = { + invitedCount: response.summary.invited, + failedCount: response.summary.errors + response.summary.invalid, + alreadyMemberCount: response.summary.alreadyMembers, + }; + + return this.results; + } catch (error) { + console.error('Error sending bulk invitations:', error); + this.error = error instanceof Error ? error.message : 'Failed to send invitations. Please try again.'; + return null; + } finally { + this.submitting = false; + } + } + + public handleCancel(): void { + this.modal?.destroy(); + this.resolveWith?.(null); + } + + public handleClose(): void { + this.modal?.destroy(); + this.resolveWith?.(this.results); + } +} + +// Export the modal utility class +export class BulkInviteModal { + public static async show(options: { + organizationId: string; + organizationName: string; + }): Promise { + return new Promise((resolve) => { + const formElement = new BulkInviteForm(); + formElement.organizationId = options.organizationId; + formElement.organizationName = options.organizationName; + formElement.resolveWith = resolve; + + plugins.deesCatalog.DeesModal.createAndShow({ + heading: 'Bulk Invite Members', + content: html`${formElement}`, + menuOptions: [ + { + name: 'Cancel', + action: async () => { + formElement.handleCancel(); + }, + }, + { + name: 'Send Invitations', + action: async () => { + const result = await formElement.handleSubmit(); + if (result) { + // Wait a bit for user to see results, then close + setTimeout(() => { + formElement.handleClose(); + }, 2000); + } + }, + }, + ], + width: 520, + }).then((modal) => { + formElement.modal = modal; + }); + }); + } +} diff --git a/ts_web/elements/account/create-org-modal.ts b/ts_web/elements/account/create-org-modal.ts index 97fb360..803d0b5 100644 --- a/ts_web/elements/account/create-org-modal.ts +++ b/ts_web/elements/account/create-org-modal.ts @@ -267,9 +267,12 @@ class CreateOrgForm extends DeesElement { 'manifest' ); - // Update state with new organization + // Update state with new organization and role const currentState = accountStateModule.accountState.getState(); currentState.organizations.push(result.resultingOrganization); + if (result.role) { + currentState.roles.push(result.role); + } accountStateModule.accountState.dispatchAction( accountStateModule.setSelectedOrg, result.resultingOrganization diff --git a/ts_web/elements/account/views/usersview.ts b/ts_web/elements/account/views/usersview.ts index 10de015..3d86a81 100644 --- a/ts_web/elements/account/views/usersview.ts +++ b/ts_web/elements/account/views/usersview.ts @@ -12,6 +12,7 @@ import { import sharedStyles, { accountDesignTokens, cardStyles, typographyStyles } from '../sharedstyles.js'; import * as accountState from '../../../states/accountstate.js'; import { IdpState } from '../../../states/idp.state.js'; +import { BulkInviteModal } from '../bulk-invite-modal.js'; declare global { interface HTMLElementTagNameMap { @@ -64,6 +65,9 @@ export class UsersView extends DeesElement { @state() accessor isAdmin: boolean = false; + @state() + accessor isOwner: boolean = false; + @state() accessor currentUserId: string = ''; @@ -75,6 +79,8 @@ export class UsersView extends DeesElement { private static readonly AVAILABLE_ROLES = ['owner', 'admin', 'editor', 'viewer', 'guest']; + private emailInputSubscribed: boolean = false; + public static styles = [ cssManager.defaultStyles, accountDesignTokens, @@ -459,16 +465,28 @@ export class UsersView extends DeesElement { ${role} `)} - ${this.isAdmin && member.userId !== this.currentUserId ? html` + ${member.userId !== this.currentUserId ? html`
- + ${this.isOwner && !member.isOwner ? html` + + ` : ''} + ${this.isAdmin ? html` + + ` : ''}
` : ''} @@ -560,23 +578,40 @@ export class UsersView extends DeesElement { .status=${this.submitting ? 'pending' : 'normal'} @click=${() => this.handleSendInvitation()} > + +
+

+ Need to invite multiple people at once? +

+ this.handleBulkImport()} + > +
`; } public async firstUpdated() { - // Subscribe to email input changes - await this.updateComplete; - const emailInput = this.shadowRoot?.querySelector('dees-input-text') as any; - if (emailInput) { - emailInput.changeSubject?.subscribe((element: any) => { - this.inviteEmail = element.value; - }); - } - await this.loadData(); } + public updated(changedProperties: Map) { + super.updated(changedProperties); + + // Subscribe to email input when Invite tab is shown + if (this.activeTab === 'invite' && !this.emailInputSubscribed) { + const emailInput = this.shadowRoot?.querySelector('.invite-form dees-input-text') as any; + if (emailInput?.changeSubject) { + emailInput.changeSubject.subscribe((element: any) => { + this.inviteEmail = element.value; + }); + this.emailInputSubscribed = true; + } + } + } + private async loadData() { this.loading = true; @@ -598,11 +633,12 @@ export class UsersView extends DeesElement { this.organizationName = selectedOrg.data.name; this.currentUserId = currentState.user?.id || ''; - // Check if current user is admin + // Check if current user is admin/owner const currentUserRole = currentState.roles.find( r => r.data.organizationId === this.organizationId && r.data.userId === this.currentUserId ); this.isAdmin = currentUserRole?.data?.roles?.some(r => ['owner', 'admin'].includes(r)) ?? false; + this.isOwner = currentUserRole?.data?.roles?.includes('owner') ?? false; // Get JWT from IdpState const idpState = await IdpState.getSingletonInstance(); @@ -818,6 +854,75 @@ export class UsersView extends DeesElement { } } + private async handleTransferOwnership(newOwnerId: string, name: string) { + const confirmed = await this.showTransferConfirmation(name); + if (!confirmed) return; + + this.submitting = true; + this.actionMessage = null; + + try { + const idpState = await IdpState.getSingletonInstance(); + const jwt = await idpState.idpClient.getJwt(); + + const request = idpState.idpClient.typedsocket.createTypedRequest( + 'transferOwnership' + ); + + const response = await request.fire({ + jwt, + organizationId: this.organizationId, + newOwnerId, + }); + + if (response.success) { + this.showMessage('success', `Ownership transferred to ${name}. You are now an admin.`); + await this.loadData(); + } else { + this.showMessage('error', response.message || 'Failed to transfer ownership.'); + } + } catch (error) { + console.error('Error transferring ownership:', error); + this.showMessage('error', 'Failed to transfer ownership. Please try again.'); + } finally { + this.submitting = false; + } + } + + private async showTransferConfirmation(name: string): Promise { + return new Promise((resolve) => { + plugins.deesCatalog.DeesModal.createAndShow({ + heading: 'Transfer Ownership', + content: html` +
+

Are you sure you want to transfer ownership to ${name}?

+

+ You will be demoted to admin role and will no longer be the owner of this organization. +

+
+ `, + menuOptions: [ + { name: 'Cancel', action: async (modal) => { modal.destroy(); resolve(false); } }, + { name: 'Transfer Ownership', action: async (modal) => { modal.destroy(); resolve(true); } }, + ], + width: 420, + }); + }); + } + + private async handleBulkImport() { + const result = await BulkInviteModal.show({ + organizationId: this.organizationId, + organizationName: this.organizationName, + }); + + if (result && result.invitedCount > 0) { + this.showMessage('success', `${result.invitedCount} invitation(s) sent successfully.`); + await this.loadData(); + this.activeTab = 'pending'; + } + } + private showMessage(type: 'success' | 'error', text: string) { this.actionMessage = { type, text }; // Auto-hide after 5 seconds diff --git a/ts_web/states/accountstate.ts b/ts_web/states/accountstate.ts index a6d1481..d52e5a1 100644 --- a/ts_web/states/accountstate.ts +++ b/ts_web/states/accountstate.ts @@ -87,6 +87,9 @@ export const manifestNewOrgName = accountState.createAction(async (statePartArg, 'manifest' ); currentState.organizations.push(result.resultingOrganization); + if (result.role) { + currentState.roles.push(result.role); + } currentState.selectedOrg = result.resultingOrganization; return currentState; });