From b63006f7bd998a2b4a95b277589e402a6726bd3a Mon Sep 17 00:00:00 2001 From: Nafees Nazik <84864519+G3root@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:16:26 +0530 Subject: [PATCH] refactor: pg-boss jobs and esign (#493) * feat: add queue utility * feat: add QUEUE_DATABASE_URL * feat: update member invite email * feat: update password reset email * feat: update share update email * feat: update data room email job * feat: update reinvite job * feat: register jobs * feat: add eSignNotificationWorker * feat: add authVerificationEmailWorker * feat: add esign confirmation job * feat: add esign pdf worker * feat: refactor name * refactor: move lib * feat: update * feat: use singleton * feat: split and register * chore: fix connection * fix: type * chore: fix type * chore: upgrade pg-boss * chore: fix type * fix: types * feat: move audit inside handler * feat: refactor sign-template * fix: remove sent status * feat: add status complete * feat: add new enums * fix: status map * fix: status * fix: job * feat: refactor esign * fix: status enum * feat: changes * chore: upgrade react email * feat: use render method --- package.json | 6 +- pnpm-lock.yaml | 1495 +++-------------- .../migration.sql | 16 + prisma/schema.prisma | 3 +- .../esign/v/[templatePublicId]/page.tsx | 27 +- src/app/updates/[publicId]/page.tsx | 4 +- .../template/canavs-toolbar/index.tsx | 2 +- .../template/template-field-form/index.tsx | 2 +- src/constants/job.ts | 2 +- src/emails/EsignConfirmationEmail.tsx | 4 +- src/emails/EsignEmail.tsx | 9 +- src/env.js | 6 + src/instrumentation.ts | 5 +- src/jobs/auth-verification-email.ts | 36 +- src/jobs/base.ts | 106 -- src/jobs/esign-complete-pdf.ts | 83 + src/jobs/esign-confirmation-email.ts | 102 +- src/jobs/esign-email.ts | 143 +- src/jobs/esign-pdf.ts | 164 +- src/jobs/member-inivite-email.ts | 58 +- src/jobs/password-reset-email.ts | 36 +- src/jobs/register.ts | 25 + src/jobs/share-data-room-email.ts | 47 +- src/jobs/share-update-email.ts | 49 +- src/jobs/start.ts | 23 - src/lib/queue.ts | 121 ++ src/providers/template-field-provider.tsx | 6 +- src/server/esign.ts | 18 +- src/services/esign-service.ts | 192 +++ .../routers/auth/procedure/forgot-password.ts | 4 +- .../routers/auth/procedure/resend-email.ts | 4 +- src/trpc/routers/auth/procedure/signup.ts | 4 +- src/trpc/routers/data-room-router/router.ts | 11 +- .../member-router/procedures/invite-member.ts | 8 +- .../member-router/procedures/re-invite.ts | 8 +- .../procedures/add-fields.ts | 20 +- .../routers/template-field-router/schema.ts | 2 +- .../procedures/get-signing-fields.tsx | 3 + .../procedures/sign-template.ts | 327 +--- .../routers/update/procedures/share-update.ts | 11 +- 40 files changed, 1095 insertions(+), 2097 deletions(-) create mode 100644 prisma/migrations/20240906132847_add_new_status/migration.sql delete mode 100644 src/jobs/base.ts create mode 100644 src/jobs/esign-complete-pdf.ts create mode 100644 src/jobs/register.ts delete mode 100644 src/jobs/start.ts create mode 100644 src/lib/queue.ts create mode 100644 src/services/esign-service.ts diff --git a/package.json b/package.json index 10c74d3f6..b303ab76e 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "@radix-ui/react-tabs": "^1.0.4", "@radix-ui/react-toolbar": "^1.0.4", "@radix-ui/react-tooltip": "^1.1.2", - "@react-email/components": "0.0.22", + "@react-email/components": "0.0.25", "@react-pdf/renderer": "^3.4.4", "@remixicon/react": "^4.0.1", "@scalar/nextjs-api-reference": "^0.4.18", @@ -96,7 +96,7 @@ "nodemailer": "^6.9.14", "papaparse": "^5.4.1", "pdf-lib": "^1.17.1", - "pg-boss": "^9.0.3", + "pg-boss": "^10.1.1", "pino": "^9.3.1", "pino-pretty": "^11.2.2", "prisma-extension-pagination": "^0.7.4", @@ -105,7 +105,7 @@ "react": "18.3.1", "react-dom": "18.2.0", "react-dropzone": "^14.2.3", - "react-email": "2.1.6", + "react-email": "3.0.1", "react-hook-form": "^7.52.1", "react-number-format": "^5.3.4", "react-pdf": "^8.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 61b4824d3..8dda89e60 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -90,8 +90,8 @@ importers: specifier: ^1.1.2 version: 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) '@react-email/components': - specifier: 0.0.22 - version: 0.0.22(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) + specifier: 0.0.25 + version: 0.0.25(react-dom@18.2.0(react@18.3.1))(react@18.3.1) '@react-pdf/renderer': specifier: ^3.4.4 version: 3.4.4(react@18.3.1) @@ -207,8 +207,8 @@ importers: specifier: ^1.17.1 version: 1.17.1 pg-boss: - specifier: ^9.0.3 - version: 9.0.3 + specifier: ^10.1.1 + version: 10.1.1 pino: specifier: ^9.3.1 version: 9.3.1 @@ -234,8 +234,8 @@ importers: specifier: ^14.2.3 version: 14.2.3(react@18.3.1) react-email: - specifier: 2.1.6 - version: 2.1.6(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.11)(eslint@9.8.0) + specifier: 3.0.1 + version: 3.0.1(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) react-hook-form: specifier: ^7.52.1 version: 7.52.1(react@18.3.1) @@ -771,12 +771,6 @@ packages: '@emnapi/runtime@1.1.1': resolution: {integrity: sha512-3bfqkzuR1KLx57nZfjr2NLnFOobvyS0aTszaEGCGqmYMVDRaGvgIZbjGSV/MHSSmLgQ/b9JFHQ5xm5WRZYd+XQ==} - '@emotion/is-prop-valid@0.8.8': - resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==} - - '@emotion/memoize@0.7.4': - resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==} - '@ericcornelissen/bash-parser@0.5.2': resolution: {integrity: sha512-4pIMTa1nEFfMXitv7oaNEWOdM+zpOZavesa5GaiWTgda6Zk32CFGxjUp/iIaN0PwgUW1yTq/fztSjbpE8SLGZQ==} engines: {node: '>=4'} @@ -1195,32 +1189,6 @@ packages: cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.4.0': - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.11.0': - resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/config-array@0.17.1': - resolution: {integrity: sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/eslintrc@3.1.0': - resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@9.8.0': - resolution: {integrity: sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/object-schema@2.1.4': - resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@faker-js/faker@8.4.1': resolution: {integrity: sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0, npm: '>=6.14.13'} @@ -1317,14 +1285,6 @@ packages: peerDependencies: react-hook-form: ^7.0.0 - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/retry@0.3.0': - resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==} - engines: {node: '>=18.18'} - '@img/sharp-darwin-arm64@0.33.4': resolution: {integrity: sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} @@ -1544,14 +1504,14 @@ packages: '@next/bundle-analyzer@14.2.3': resolution: {integrity: sha512-Z88hbbngMs7njZKI8kTJIlpdLKYfMSLwnsqYe54AP4aLmgL70/Ynx/J201DQ+q2Lr6FxFw1uCeLGImDrHOl2ZA==} - '@next/env@14.1.4': - resolution: {integrity: sha512-e7X7bbn3Z6DWnDi75UWn+REgAbLEqxI8Tq2pkFOFAMpWAWApz/YCUhtWMWn410h8Q2fYiYL7Yg5OlxMOCfFjJQ==} + '@next/env@14.2.3': + resolution: {integrity: sha512-W7fd7IbkfmeeY2gXrzJYDx8D2lWKbVoTIj1o1ScPHNzvp30s1AuoEFSdr39bC5sjxJaxTtq3OTCZboNp0lNWHA==} '@next/env@14.2.4': resolution: {integrity: sha512-3EtkY5VDkuV2+lNmKlbkibIJxcO4oIHEhBWne6PaAp+76J9KoSsGvNikp6ivzAT8dhhBMYrm6op2pS1ApG0Hzg==} - '@next/swc-darwin-arm64@14.1.4': - resolution: {integrity: sha512-ubmUkbmW65nIAOmoxT1IROZdmmJMmdYvXIe8211send9ZYJu+SqxSnJM4TrPj9wmL6g9Atvj0S/2cFmMSS99jg==} + '@next/swc-darwin-arm64@14.2.3': + resolution: {integrity: sha512-3pEYo/RaGqPP0YzwnlmPN2puaF2WMLM3apt5jLW2fFdXD9+pqcoTzRk+iZsf8ta7+quAe4Q6Ms0nR0SFGFdS1A==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -1562,8 +1522,8 @@ packages: cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@14.1.4': - resolution: {integrity: sha512-b0Xo1ELj3u7IkZWAKcJPJEhBop117U78l70nfoQGo4xUSvv0PJSTaV4U9xQBLvZlnjsYkc8RwQN1HoH/oQmLlQ==} + '@next/swc-darwin-x64@14.2.3': + resolution: {integrity: sha512-6adp7waE6P1TYFSXpY366xwsOnEXM+y1kgRpjSRVI2CBDOcbRjsJ67Z6EgKIqWIue52d2q/Mx8g9MszARj8IEA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -1574,8 +1534,8 @@ packages: cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@14.1.4': - resolution: {integrity: sha512-457G0hcLrdYA/u1O2XkRMsDKId5VKe3uKPvrKVOyuARa6nXrdhJOOYU9hkKKyQTMru1B8qEP78IAhf/1XnVqKA==} + '@next/swc-linux-arm64-gnu@14.2.3': + resolution: {integrity: sha512-cuzCE/1G0ZSnTAHJPUT1rPgQx1w5tzSX7POXSLaS7w2nIUJUD+e25QoXD/hMfxbsT9rslEXugWypJMILBj/QsA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -1586,8 +1546,8 @@ packages: cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@14.1.4': - resolution: {integrity: sha512-l/kMG+z6MB+fKA9KdtyprkTQ1ihlJcBh66cf0HvqGP+rXBbOXX0dpJatjZbHeunvEHoBBS69GYQG5ry78JMy3g==} + '@next/swc-linux-arm64-musl@14.2.3': + resolution: {integrity: sha512-0D4/oMM2Y9Ta3nGuCcQN8jjJjmDPYpHX9OJzqk42NZGJocU2MqhBq5tWkJrUQOQY9N+In9xOdymzapM09GeiZw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -1598,8 +1558,8 @@ packages: cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@14.1.4': - resolution: {integrity: sha512-BapIFZ3ZRnvQ1uWbmqEGJuPT9cgLwvKtxhK/L2t4QYO7l+/DxXuIGjvp1x8rvfa/x1FFSsipERZK70pewbtJtw==} + '@next/swc-linux-x64-gnu@14.2.3': + resolution: {integrity: sha512-ENPiNnBNDInBLyUU5ii8PMQh+4XLr4pG51tOp6aJ9xqFQ2iRI6IH0Ds2yJkAzNV1CfyagcyzPfROMViS2wOZ9w==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -1610,8 +1570,8 @@ packages: cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@14.1.4': - resolution: {integrity: sha512-mqVxTwk4XuBl49qn2A5UmzFImoL1iLm0KQQwtdRJRKl21ylQwwGCxJtIYo2rbfkZHoSKlh/YgztY0qH3wG1xIg==} + '@next/swc-linux-x64-musl@14.2.3': + resolution: {integrity: sha512-BTAbq0LnCbF5MtoM7I/9UeUu/8ZBY0i8SFjUMCbPDOLv+un67e2JgyN4pmgfXBwy/I+RHu8q+k+MCkDN6P9ViQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -1622,8 +1582,8 @@ packages: cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@14.1.4': - resolution: {integrity: sha512-xzxF4ErcumXjO2Pvg/wVGrtr9QQJLk3IyQX1ddAC/fi6/5jZCZ9xpuL9Tzc4KPWMFq8GGWFVDMshZOdHGdkvag==} + '@next/swc-win32-arm64-msvc@14.2.3': + resolution: {integrity: sha512-AEHIw/dhAMLNFJFJIJIyOFDzrzI5bAjI9J26gbO5xhAKHYTZ9Or04BesFPXiAYXDNdrwTP2dQceYA4dL1geu8A==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -1634,8 +1594,8 @@ packages: cpu: [arm64] os: [win32] - '@next/swc-win32-ia32-msvc@14.1.4': - resolution: {integrity: sha512-WZiz8OdbkpRw6/IU/lredZWKKZopUMhcI2F+XiMAcPja0uZYdMTZQRoQ0WZcvinn9xZAidimE7tN9W5v9Yyfyw==} + '@next/swc-win32-ia32-msvc@14.2.3': + resolution: {integrity: sha512-vga40n1q6aYb0CLrM+eEmisfKCR45ixQYXuBXxOOmmoV8sYST9k7E3US32FsY+CkkF7NtzdcebiFT4CHuMSyZw==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -1646,8 +1606,8 @@ packages: cpu: [ia32] os: [win32] - '@next/swc-win32-x64-msvc@14.1.4': - resolution: {integrity: sha512-4Rto21sPfw555sZ/XNLqfxDUNeLhNYGO2dlPqsnuCg8N8a2a9u1ltqBOPQ4vj1Gf7eJC0W2hHG2eYUHuiXgY2w==} + '@next/swc-win32-x64-msvc@14.2.3': + resolution: {integrity: sha512-Q1/zm43RWynxrO7lW4ehciQVj+5ePBhOK+/K2P7pLFX3JaJ/IZVC69SHidrmZSOkqz7ECIOhhy7XhAFG4JYyHA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1928,9 +1888,6 @@ packages: '@prisma/instrumentation@5.17.0': resolution: {integrity: sha512-c1Sle4ji8aasMcYfBBHFM56We4ljfenVtRmS8aY06BllS7SoU6SmJBwG7vil+GHiR0Yrh+t9iBwt4AY0Jr4KNQ==} - '@radix-ui/colors@1.0.1': - resolution: {integrity: sha512-xySw8f0ZVsAEP+e7iLl3EvcBXX7gsIlC1Zso/sPBW9gIWerBTgz6axrjU+MZ39wD+WFi5h5zdWpsg3+hwt2Qsg==} - '@radix-ui/number@1.0.1': resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} @@ -2506,19 +2463,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-toggle-group@1.1.0': - resolution: {integrity: sha512-PpTJV68dZU2oqqgq75Uzto5o/XfOVgkrJ9rulVmfTKxWp3HfUjHE6CP/WLRR4AzPX9HWxw7vFow2me85Yu+Naw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-toggle@1.0.3': resolution: {integrity: sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==} peerDependencies: @@ -2532,19 +2476,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-toggle@1.1.0': - resolution: {integrity: sha512-gwoxaKZ0oJ4vIgzsfESBuSgJNdc0rv12VhHgcqN0TEJmmZixXG/2XpsLK8kzNWYcnaoRIEEQc0bEi3dIvdUpjw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-toolbar@1.0.4': resolution: {integrity: sha512-tBgmM/O7a07xbaEkYJWYTXkIdU/1pW4/KZORR43toC/4XWyBCURK0ei9kMUdp+gTPPKBgYLxXmRSH1EVcIDp8Q==} peerDependencies: @@ -2558,19 +2489,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-tooltip@1.1.1': - resolution: {integrity: sha512-LLE8nzNE4MzPMw3O2zlVlkLFid3y9hMUs7uCbSHyKSo+tCN4yMCf+ZCCcfrYgsOC0TiHBPQ1mtpJ2liY3ZT3SQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-tooltip@1.1.2': resolution: {integrity: sha512-9XRsLwe6Yb9B/tlnYCPVUd/TFS4J7HuOZW345DCeC6vKIxQGMZdx21RK4VoZauPD5frgkXTYVS5y90L+3YBn4w==} peerDependencies: @@ -2742,130 +2660,130 @@ packages: '@radix-ui/rect@1.1.0': resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} - '@react-email/body@0.0.9': - resolution: {integrity: sha512-bSGF6j+MbfQKYnnN+Kf57lGp/J+ci+435OMIv/BKAtfmNzHL+ptRrsINJELiO8QzwnZmQjTGKSMAMMJiQS+xwQ==} + '@react-email/body@0.0.10': + resolution: {integrity: sha512-dMJyL9aU25ieatdPtVjCyQ/WHZYHwNc+Hy/XpF8Cc18gu21cUynVEeYQzFSeigDRMeBQ3PGAyjVDPIob7YlGwA==} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/button@0.0.16': - resolution: {integrity: sha512-paptUerzDhKHEUmBuT0UecCoqo3N6ZQSyDKC1hFALTwKReGW2xQATisinho9Ybh9ZGw6IZ3n1nGtmX5k2sX70Q==} + '@react-email/button@0.0.17': + resolution: {integrity: sha512-ioHdsk+BpGS/PqjU6JS7tUrVy9yvbUx92Z+Cem2+MbYp55oEwQ9VHf7u4f5NoM0gdhfKSehBwRdYlHt/frEMcg==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/code-block@0.0.6': - resolution: {integrity: sha512-i+TEeI7AyG1pmtO2Mr+TblV08zQnOtTlYB/v45kFMlDWWKTkvIV33oLRqLYOFhCIvoO5fDZA9T+4m6PvhmcNwQ==} + '@react-email/code-block@0.0.9': + resolution: {integrity: sha512-Zrhc71VYrSC1fVXJuaViKoB/dBjxLw6nbE53Bm/eUuZPdnnZ1+ZUIh8jfaRKC5MzMjgnLGQTweGXVnfIrhyxtQ==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/code-inline@0.0.3': - resolution: {integrity: sha512-SY5Nn4KhjcqqEBHvUwFlOLNmUT78elIGR+Y14eg02LrVKQJ38mFCfXNGDLk4wbP/2dnidkLYq9+60nf7mFMhnQ==} + '@react-email/code-inline@0.0.4': + resolution: {integrity: sha512-zj3oMQiiUCZbddSNt3k0zNfIBFK0ZNDIzzDyBaJKy6ZASTtWfB+1WFX0cpTX8q0gUiYK+A94rk5Qp68L6YXjXQ==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/column@0.0.11': - resolution: {integrity: sha512-KvrPuQFn0hlItRRL3vmRuOJgKG+8I0oO9HM5ReLMi5Ns313JSEQogCJaXuOEFkOVeuu5YyY6zy/+5Esccc1AxQ==} + '@react-email/column@0.0.12': + resolution: {integrity: sha512-Rsl7iSdDaeHZO938xb+0wR5ud0Z3MVfdtPbNKJNojZi2hApwLAQXmDrnn/AcPDM5Lpl331ZljJS8vHTWxxkvKw==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/components@0.0.22': - resolution: {integrity: sha512-GO6F+fS3c3aQ6OnqL8esQ/KqtrPGwz80U6uQ8Nd/ETpgFt7y1PXvSGfr8v12wyLffAagdowc/JjoThfIr0L6aA==} + '@react-email/components@0.0.25': + resolution: {integrity: sha512-lnfVVrThEcET5NPoeaXvrz9UxtWpGRcut2a07dLbyKgNbP7vj/cXTI5TuHtanCvhCddFpMDnElNRghDOfPzwUg==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/container@0.0.13': - resolution: {integrity: sha512-ftke0N1FZl8MX3XXxXiiOaiJOnrQz7ZXUyqNj81K+BK+DePWIVaSmgK6Bu8fFnsgwdKuBdqjZTEtF4sIkU3FuQ==} + '@react-email/container@0.0.14': + resolution: {integrity: sha512-NgoaJJd9tTtsrveL86Ocr/AYLkGyN3prdXKd/zm5fQpfDhy/NXezyT3iF6VlwAOEUIu64ErHpAJd+P6ygR+vjg==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/font@0.0.7': - resolution: {integrity: sha512-R0/mfUV/XcUQIALjZUFT9GP+XGmIP1KPz20h9rpS5e4ji6VkQ3ENWlisxrdK5U+KA9iZQrlan+/6tUoTJ9bFsg==} + '@react-email/font@0.0.8': + resolution: {integrity: sha512-fSBEqYyVPAyyACBBHcs3wEYzNknpHMuwcSAAKE8fOoDfGqURr/vSxKPdh4tOa9z7G4hlcEfgGrCYEa2iPT22cw==} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/head@0.0.10': - resolution: {integrity: sha512-VoH399w0/i3dJFnwH0Ixf9BTuiWhSA/y8PpsCJ7CPw8Mv8WNBqMAAsw0rmrITYI8uPd15LZ2zk2uwRDvqasMRw==} + '@react-email/head@0.0.11': + resolution: {integrity: sha512-skw5FUgyamIMK+LN+fZQ5WIKQYf0dPiRAvsUAUR2eYoZp9oRsfkIpFHr0GWPkKAYjFEj+uJjaxQ/0VzQH7svVg==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/heading@0.0.13': - resolution: {integrity: sha512-MYDzjJwljKHBLueLuyqkaHxu6N4aGOL1ms2NNyJ9WXC9mmBnLs4Y/QEf9SjE4Df3AW4iT9uyfVHuaNUb7uq5QA==} + '@react-email/heading@0.0.14': + resolution: {integrity: sha512-jZM7IVuZOXa0G110ES8OkxajPTypIKlzlO1K1RIe1auk76ukQRiCg1IRV4HZlWk1GGUbec5hNxsvZa2kU8cb9w==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/hr@0.0.9': - resolution: {integrity: sha512-Rte+EZL3ptH3rkVU3a7fh8/06mZ6Q679tDaWDjsw3878RQC9afWqUPp5lwgA/1pTouLmJlDs2BjRnV6H84O7iw==} + '@react-email/hr@0.0.10': + resolution: {integrity: sha512-3AA4Yjgl3zEid/KVx6uf6TuLJHVZvUc2cG9Wm9ZpWeAX4ODA+8g9HyuC0tfnjbRsVMhMcCGiECuWWXINi+60vA==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/html@0.0.9': - resolution: {integrity: sha512-NB74xwWaOJZxhpiy6pzkhHvugBa2vvmUa0KKnSwOEIX+WEQH8wj5UUhRN4F+Pmkiqz3QBTETUJiSsNWWFtrHgA==} + '@react-email/html@0.0.10': + resolution: {integrity: sha512-06uiuSKJBWQJfhCKv4MPupELei4Lepyz9Sth7Yq7Fq29CAeB1ejLgKkGqn1I+FZ72hQxPLdYF4iq4yloKv3JCg==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/img@0.0.9': - resolution: {integrity: sha512-zDlQWmlSANb2dBYhDaKD12Z4xaGD5mEf3peawBYHGxYySzMLwRT2ANGvFqpDNd7iT0C5po+/9EWR8fS1dLy0QQ==} + '@react-email/img@0.0.10': + resolution: {integrity: sha512-pJ8glJjDNaJ53qoM95pvX9SK05yh0bNQY/oyBKmxlBDdUII6ixuMc3SCwYXPMl+tgkQUyDgwEBpSTrLAnjL3hA==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/link@0.0.9': - resolution: {integrity: sha512-rRqWGPUTGFwwtMCtsdCHNh0ewOsd4UBG/D12UcwJYFKRb0U6hUG/6VJZE3tB1QYZpLIESdvOLL6ztznh+D749g==} + '@react-email/link@0.0.10': + resolution: {integrity: sha512-tva3wvAWSR10lMJa9fVA09yRn7pbEki0ZZpHE6GD1jKbFhmzt38VgLO9B797/prqoDZdAr4rVK7LJFcdPx3GwA==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/markdown@0.0.11': - resolution: {integrity: sha512-KeDTS0bAvvtgavYAIAmxKpRxWUSr1/jufckDzu9g4QsQtth8wYaSR5wCPXuTPmhFgJMIlNSlOiBnVp+oRbDtKA==} + '@react-email/markdown@0.0.12': + resolution: {integrity: sha512-wsuvj1XAb6O63aizCLNEeqVgKR3oFjAwt9vjfg2y2oh4G1dZeo8zonZM2x1fmkEkBZhzwSHraNi70jSXhA3A9w==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/preview@0.0.10': - resolution: {integrity: sha512-bRrv8teMMBlF7ttLp1zZUejkPUzrwMQXrigdagtEBOqsB8HxvJU2MR6Yyb3XOqBYldaIDOQJ1z61zyD2wRlKAw==} + '@react-email/preview@0.0.11': + resolution: {integrity: sha512-7O/CT4b16YlSGrj18htTPx3Vbhu2suCGv/cSe5c+fuSrIM/nMiBSZ3Js16Vj0XJbAmmmlVmYFZw9L20wXJ+LjQ==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/render@0.0.17': - resolution: {integrity: sha512-xBQ+/73+WsGuXKY7r1U73zMBNV28xdV0cp9cFjhNYipBReDHhV97IpA6v7Hl0dDtDzt+yS/72dY5vYXrF1v8NA==} + '@react-email/render@1.0.1': + resolution: {integrity: sha512-W3gTrcmLOVYnG80QuUp22ReIT/xfLsVJ+n7ghSlG2BITB8evNABn1AO2rGQoXuK84zKtDAlxCdm3hRyIpZdGSA==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 - react-dom: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/row@0.0.9': - resolution: {integrity: sha512-ZDASHVvyKrWBS00o5pSH5khfMf46UtZhrHcSAfPSiC4nj7R8A0bf+3Wmbk8YmsaV+qWXUCUSHWwIAAlMRnJoAA==} + '@react-email/row@0.0.10': + resolution: {integrity: sha512-jPyEhG3gsLX+Eb9U+A30fh0gK6hXJwF4ghJ+ZtFQtlKAKqHX+eCpWlqB3Xschd/ARJLod8WAswg0FB+JD9d0/A==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/section@0.0.13': - resolution: {integrity: sha512-McsCQ5NQlNWEMEAR3EtCxHgRhxGmLD+jPvj7A3FD7y2X3fXG0hbmUGX12B63rIywSWjJoQi6tojx/8RpzbyeTA==} + '@react-email/section@0.0.14': + resolution: {integrity: sha512-+fYWLb4tPU1A/+GE5J1+SEMA7/wR3V30lQ+OR9t2kAJqNrARDbMx0bLnYnR1QL5TiFRz0pCF05SQUobk6gHEDQ==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/tailwind@0.0.19': - resolution: {integrity: sha512-bA0w4D7mSNowxWhcO0jBJauFIPf2Ok7QuKlrHwCcxyX35L2pb5D6ZmXYOrD9C6ADQuVz5oEX+oed3zpSLROgPg==} + '@react-email/tailwind@0.1.0': + resolution: {integrity: sha512-qysVUEY+M3SKUvu35XDpzn7yokhqFOT3tPU6Mj/pgc62TL5tQFj6msEbBtwoKs2qO3WZvai0DIHdLhaOxBQSow==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/text@0.0.9': - resolution: {integrity: sha512-UNFPGerER3zywpb1ODOS2VgHP7rgOmiTxMHn75pjvQf/gi3/jN9edEQLYvRgPv/mNn4IpJFkOrlP8jcammLeew==} + '@react-email/text@0.0.10': + resolution: {integrity: sha512-wNAnxeEAiFs6N+SxS0y6wTJWfewEzUETuyS2aZmT00xk50VijwyFRuhm4sYSjusMyshevomFwz5jNISCxRsGWw==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^18.2.0 + react: ^18.0 || ^19.0 || ^19.0.0-rc '@react-pdf/fns@2.2.1': resolution: {integrity: sha512-s78aDg0vDYaijU5lLOCsUD+qinQbfOvcNeaoX9AiE7+kZzzCo6B/nX+l48cmt9OosJmvZvE9DWR9cLhrhOi2pA==} @@ -3485,75 +3403,6 @@ packages: resolution: {integrity: sha512-HhstGRUz/4JdbZpb26OcOf8Qb/cFR02arvHvgz4sPFLSnI6ZNHC53Jc6JP/FGNwxtrF719YyUnK0gGy4oyhucQ==} engines: {node: '>=12.16'} - '@swc/core-darwin-arm64@1.3.101': - resolution: {integrity: sha512-mNFK+uHNPRXSnfTOG34zJOeMl2waM4hF4a2NY7dkMXrPqw9CoJn4MwTXJcyMiSz1/BnNjjTCHF3Yhj0jPxmkzQ==} - engines: {node: '>=10'} - cpu: [arm64] - os: [darwin] - - '@swc/core-darwin-x64@1.3.101': - resolution: {integrity: sha512-B085j8XOx73Fg15KsHvzYWG262bRweGr3JooO1aW5ec5pYbz5Ew9VS5JKYS03w2UBSxf2maWdbPz2UFAxg0whw==} - engines: {node: '>=10'} - cpu: [x64] - os: [darwin] - - '@swc/core-linux-arm-gnueabihf@1.3.101': - resolution: {integrity: sha512-9xLKRb6zSzRGPqdz52Hy5GuB1lSjmLqa0lST6MTFads3apmx4Vgs8Y5NuGhx/h2I8QM4jXdLbpqQlifpzTlSSw==} - engines: {node: '>=10'} - cpu: [arm] - os: [linux] - - '@swc/core-linux-arm64-gnu@1.3.101': - resolution: {integrity: sha512-oE+r1lo7g/vs96Weh2R5l971dt+ZLuhaUX+n3BfDdPxNHfObXgKMjO7E+QS5RbGjv/AwiPCxQmbdCp/xN5ICJA==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux] - - '@swc/core-linux-arm64-musl@1.3.101': - resolution: {integrity: sha512-OGjYG3H4BMOTnJWJyBIovCez6KiHF30zMIu4+lGJTCrxRI2fAjGLml3PEXj8tC3FMcud7U2WUn6TdG0/te2k6g==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux] - - '@swc/core-linux-x64-gnu@1.3.101': - resolution: {integrity: sha512-/kBMcoF12PRO/lwa8Z7w4YyiKDcXQEiLvM+S3G9EvkoKYGgkkz4Q6PSNhF5rwg/E3+Hq5/9D2R+6nrkF287ihg==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux] - - '@swc/core-linux-x64-musl@1.3.101': - resolution: {integrity: sha512-kDN8lm4Eew0u1p+h1l3JzoeGgZPQ05qDE0czngnjmfpsH2sOZxVj1hdiCwS5lArpy7ktaLu5JdRnx70MkUzhXw==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux] - - '@swc/core-win32-arm64-msvc@1.3.101': - resolution: {integrity: sha512-9Wn8TTLWwJKw63K/S+jjrZb9yoJfJwCE2RV5vPCCWmlMf3U1AXj5XuWOLUX+Rp2sGKau7wZKsvywhheWm+qndQ==} - engines: {node: '>=10'} - cpu: [arm64] - os: [win32] - - '@swc/core-win32-ia32-msvc@1.3.101': - resolution: {integrity: sha512-onO5KvICRVlu2xmr4//V2je9O2XgS1SGKpbX206KmmjcJhXN5EYLSxW9qgg+kgV5mip+sKTHTAu7IkzkAtElYA==} - engines: {node: '>=10'} - cpu: [ia32] - os: [win32] - - '@swc/core-win32-x64-msvc@1.3.101': - resolution: {integrity: sha512-T3GeJtNQV00YmiVw/88/nxJ/H43CJvFnpvBHCVn17xbahiVUOPOduh3rc9LgAkKiNt/aV8vU3OJR+6PhfMR7UQ==} - engines: {node: '>=10'} - cpu: [x64] - os: [win32] - - '@swc/core@1.3.101': - resolution: {integrity: sha512-w5aQ9qYsd/IYmXADAnkXPGDMTqkQalIi+kfFf/MHRKTpaOL7DHjMXwPp/n8hJ0qNjRvchzmPtOqtPBiER50d8A==} - engines: {node: '>=10'} - peerDependencies: - '@swc/helpers': ^0.5.0 - peerDependenciesMeta: - '@swc/helpers': - optional: true - '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} @@ -3566,15 +3415,9 @@ packages: '@swc/helpers@0.5.11': resolution: {integrity: sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==} - '@swc/helpers@0.5.2': - resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} - '@swc/helpers@0.5.5': resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} - '@swc/types@0.1.12': - resolution: {integrity: sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==} - '@t3-oss/env-core@0.10.1': resolution: {integrity: sha512-GcKZiCfWks5CTxhezn9k5zWX3sMDIYf6Kaxy2Gx9YEQftFcz8hDRN56hcbylyAO3t4jQnQ5ifLawINsNgCDpOg==} peerDependencies: @@ -3961,9 +3804,6 @@ packages: '@types/pg@8.6.1': resolution: {integrity: sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==} - '@types/prismjs@1.26.4': - resolution: {integrity: sha512-rlAnzkW2sZOjbqZ743IHUhFcvzaGbqijwOu8QZnZCjfQzBqFE3s4lOTJEsxikImav9uzz/42I+O7YUs1mWgMlg==} - '@types/prop-types@15.7.12': resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} @@ -3976,15 +3816,9 @@ packages: '@types/react-dom@18.3.0': resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} - '@types/react@18.2.47': - resolution: {integrity: sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==} - '@types/react@18.3.3': resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} - '@types/scheduler@0.23.0': - resolution: {integrity: sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==} - '@types/send@0.17.4': resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} @@ -4009,9 +3843,6 @@ packages: '@types/web-bluetooth@0.0.20': resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} - '@types/webpack@5.28.5': - resolution: {integrity: sha512-wR87cgvxj3p6D0Crt1r5avwqffqPXUkNlnQ1mjU93G7gCuFjufZR4I6j8cz5g1F1tTYpfOOFvly+cmIQwL9wvw==} - '@uiw/codemirror-themes@4.22.2': resolution: {integrity: sha512-gsLHn6SUuV5iboBvGrM7YimzLFHQmsNlkGIYs3UaVUJTo/A/ZrKoSJNyPziShLRjBXA2UwKdBTIU6VhHyyaChw==} peerDependencies: @@ -4371,11 +4202,6 @@ packages: peerDependencies: acorn: ^8 - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.2: resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} engines: {node: '>=0.4.0'} @@ -4513,13 +4339,6 @@ packages: resolution: {integrity: sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==} engines: {node: '>=4'} - autoprefixer@10.4.14: - resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 - autoprefixer@10.4.19: resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==} engines: {node: ^10 || ^12 || >=14} @@ -4609,10 +4428,6 @@ packages: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - camelcase-css@2.0.1: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} @@ -4662,10 +4477,6 @@ packages: check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} - chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} - chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -4723,10 +4534,6 @@ packages: resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} engines: {node: '>=0.8'} - clsx@1.2.1: - resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} - engines: {node: '>=6'} - clsx@2.0.0: resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} engines: {node: '>=6'} @@ -4971,9 +4778,6 @@ packages: deep-freeze@0.0.1: resolution: {integrity: sha512-Z+z8HiAvsGwmjqlphnHW5oz6yWlOwu6EQfFTjmeTWlDeda3FS2yv3jhq35TX/ewmsnqB+RX2IdsIOyjJCQN5tg==} - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -4988,10 +4792,6 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - delay@5.0.0: - resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} - engines: {node: '>=10'} - delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -5052,10 +4852,6 @@ packages: domutils@3.1.0: resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} - dotenv@16.0.3: - resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} - engines: {node: '>=12'} - dotenv@16.4.5: resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} @@ -5094,9 +4890,6 @@ packages: end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - engine.io-client@6.5.4: - resolution: {integrity: sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==} - engine.io-parser@5.2.3: resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} engines: {node: '>=10.0.0'} @@ -5155,51 +4948,10 @@ packages: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} - eslint-config-prettier@9.0.0: - resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - - eslint-config-turbo@1.10.12: - resolution: {integrity: sha512-z3jfh+D7UGYlzMWGh+Kqz++hf8LOE96q3o5R8X4HTjmxaBWlLAWG+0Ounr38h+JLR2TJno0hU9zfzoPNkR9BdA==} - peerDependencies: - eslint: '>6.6.0' - - eslint-plugin-turbo@1.10.12: - resolution: {integrity: sha512-uNbdj+ohZaYo4tFJ6dStRXu2FZigwulR1b3URPXe0Q8YaE7thuekKNP+54CHtZPH9Zey9dmDx5btAQl9mfzGOw==} - peerDependencies: - eslint: '>6.6.0' - eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} - eslint-scope@8.0.2: - resolution: {integrity: sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@4.0.0: - resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint@9.8.0: - resolution: {integrity: sha512-K8qnZ/QJzT2dLKdZJVX6W4XOwBzutMYmt0lqUS+JdXgd+HTYFlonFgkJ8s44d/zMPPCnOOk0kMWCApCPhiOy9A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - - espree@10.1.0: - resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} - engines: {node: '>=0.10'} - esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -5218,10 +4970,6 @@ packages: estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} @@ -5267,9 +5015,6 @@ packages: fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-redact@3.5.0: resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} engines: {node: '>=6'} @@ -5353,17 +5098,6 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - framer-motion@10.17.4: - resolution: {integrity: sha512-CYBSs6cWfzcasAX8aofgKFZootmkQtR4qxbfTOksBLny/lbUfkGbQAFOS3qnl6Uau1N9y8tUpI7mVIrHgkFjLQ==} - peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - fs-extra@11.1.1: resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} engines: {node: '>=14.14'} @@ -5439,11 +5173,6 @@ packages: glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.3.15: - resolution: {integrity: sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==} - engines: {node: '>=16 || 14 >=14.18'} - hasBin: true - glob@10.3.4: resolution: {integrity: sha512-6LFElP3A+i/Q8XQKEvZjkEWEOTgAIALR9AO2rwT8bgPhDd1anmqDJDZ6lLddI4ehxxxR1S5RIqKe1uapMQfYaQ==} engines: {node: '>=16 || 14 >=14.17'} @@ -5465,10 +5194,6 @@ packages: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} @@ -5687,20 +5412,12 @@ packages: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} - import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - import-in-the-middle@1.7.1: resolution: {integrity: sha512-1LrZPDtW+atAxH42S6288qyDFNQ2YCty+2mxEPRtfazH6Z5QwkaBSTS2ods7hnVJioF6rkRfNoA6A/MstpFXLg==} import-in-the-middle@1.9.1: resolution: {integrity: sha512-E+3tEOutU1MV0mxhuCwfSPNNWRkbTJ3/YyL5be+blNIbHwZc53uYHQfuIhAU77xWR0BoF2eT7cqDJ6VlU5APPg==} - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} @@ -5806,10 +5523,6 @@ packages: resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==} engines: {node: '>=0.10.0'} - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} @@ -5923,9 +5636,6 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -5967,10 +5677,6 @@ packages: resolution: {integrity: sha512-puehA3YKku3osqPlNuzGDUHq8WpwXupUg1V6NXdV38G+gr+gkBwFC8g1b/+YcIvp8gnqVIus+eJCH/eGsRmJNw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - lib0@0.2.94: resolution: {integrity: sha512-hZ3p54jL4Wpu7IOg26uC7dnEWiMyNlUrb9KoG7+xYs45WkQwpVvKFndVq2+pqLYKe1u8Fp3+zAfZHVvTK34PvQ==} engines: {node: '>=16'} @@ -6457,10 +6163,6 @@ packages: resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} engines: {node: '>=8'} - minipass@7.1.1: - resolution: {integrity: sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==} - engines: {node: '>=16 || 14 >=14.17'} - minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} @@ -6514,9 +6216,6 @@ packages: engines: {node: ^18 || >=20} hasBin: true - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} @@ -6538,18 +6237,21 @@ packages: next-nprogress-bar@2.3.13: resolution: {integrity: sha512-eJQDvPSUwZ2yRyNKqAH6xTFI4RtIFvs+qtY8essTtfooyaxLGmkanEO7vL83U166bullMtVpixD6FQk5SQkhMw==} - next@14.1.4: - resolution: {integrity: sha512-1WTaXeSrUwlz/XcnhGTY7+8eiaFvdet5z9u3V2jb+Ek1vFo0VhHKSAIJvDWfQpttWjnyw14kBeq28TPq7bTeEQ==} + next@14.2.3: + resolution: {integrity: sha512-dowFkFTR8v79NPJO4QsBUtxv0g9BrS/phluVpMAt2ku7H+cbcBJlopXjkWlwxrk/xGqMemr7JkGPGemPrLLX7A==} engines: {node: '>=18.17.0'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.41.2 react: ^18.2.0 react-dom: ^18.2.0 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': optional: true + '@playwright/test': + optional: true sass: optional: true @@ -6683,10 +6385,6 @@ packages: peerDependencies: '@opentelemetry/api': ^1.6.0 - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - ora@5.4.1: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} @@ -6726,10 +6424,6 @@ packages: papaparse@5.4.1: resolution: {integrity: sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==} - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - parse-ms@3.0.0: resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} engines: {node: '>=12'} @@ -6793,9 +6487,9 @@ packages: peberminta@0.9.0: resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==} - pg-boss@9.0.3: - resolution: {integrity: sha512-cUWUiv3sr563yNy0nCZ25Tv5U0m59Y9MhX/flm0vTR012yeVCrqpfboaZP4xFOQPdWipMJpuu4g94HR0SncTgw==} - engines: {node: '>=16'} + pg-boss@10.1.1: + resolution: {integrity: sha512-2t7gz5nEUYFabj8czWWFRUSyPDQ5t+K/EF5l9Q5lHn2iwyPPKgIfwK+8LKgRfyHRUePTDQhogsGcwOlNczfZ5Q==} + engines: {node: '>=20'} pg-cloudflare@1.1.1: resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} @@ -6924,10 +6618,6 @@ packages: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} - postcss@8.4.38: - resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.4.40: resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==} engines: {node: ^10 || ^12 || >=14} @@ -6956,10 +6646,6 @@ packages: preact@10.22.0: resolution: {integrity: sha512-RRurnSjJPj4rp5K6XoP45Ui33ncb7e4H7WiOHVpjbkvqvA3U+N8Z6Qbo0AE6leGYBV66n8EhEaFixvIu3SkxFw==} - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - pretty-bytes@6.1.1: resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} engines: {node: ^14.13.1 || >=16.0.0} @@ -6983,11 +6669,6 @@ packages: resolution: {integrity: sha512-E9e9HJ9R9NasGOgPaPE8VMeiPKAyWR5jcFpNnwIejslIhWqdqOrb2wShBsncMPUb+BcCd2OPYfh7p2W6oemTng==} engines: {node: '>=18'} - prism-react-renderer@2.1.0: - resolution: {integrity: sha512-I5cvXHjA1PVGbGm1MsWCpvBCRrYyxEri0MC7/JbfIfYfcXAxHyO5PaUjs3A8H5GW6kJcLhTHxxMaOZZpRZD2iQ==} - peerDependencies: - react: '>=16.0.0' - prisma-extension-pagination@0.7.4: resolution: {integrity: sha512-MmfyinDbcTucvttlO8UOrLqKW7DxlXe3ToiUZcLbvhGHHPewHKKWvucVnLHsYSzEIbEE1YfK/hsYdmpoRzkAAg==} peerDependencies: @@ -7160,8 +6841,8 @@ packages: peerDependencies: react: '>= 16.8 || 18.0.0' - react-email@2.1.6: - resolution: {integrity: sha512-BtR9VI1CMq4953wfiBmzupKlWcRThaWG2dDgl1vWAllK3tNNmJNerwY4VlmASRDQZE3LpLXU3+lf8N/VAKdbZQ==} + react-email@3.0.1: + resolution: {integrity: sha512-G4Bkx2ULIScy/0Z8nnWywHt0W1iTkaYCdh9rWNuQ3eVZ6B3ttTUDE9uUy3VNQ8dtQbmG0cpt8+XmImw7mMBW6Q==} engines: {node: '>=18.0.0'} hasBin: true @@ -7390,10 +7071,6 @@ packages: resolution: {integrity: sha512-nQFEv9gRw6SJAwWD2LrL0NmQvAcO7FBwJbwmr2ttPAacfy0xuiOjE5zt+zM4xDyuyvUaxBi/9gb2SoCyNEVJcw==} engines: {node: '>=8.6.0'} - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -7566,37 +7243,23 @@ packages: socket.io-adapter@2.5.5: resolution: {integrity: sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==} - socket.io-client@4.7.3: - resolution: {integrity: sha512-nU+ywttCyBitXIl9Xe0RSEfek4LneYkJxCeNnKCuhwoH4jGXO1ipIUw/VA/+Vvv2G1MTym11fzFC0SxkrcfXDw==} - engines: {node: '>=10.0.0'} - socket.io-parser@4.2.4: resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} engines: {node: '>=10.0.0'} - socket.io@4.7.3: - resolution: {integrity: sha512-SE+UIQXBQE+GPG2oszWMlsEmWtHVqw/h1VrYJGK5/MC7CH5p58N448HwIrtREcvR4jfdOJAY4ieQfxMr55qbbw==} + socket.io@4.7.5: + resolution: {integrity: sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==} engines: {node: '>=10.2.0'} sonic-boom@4.0.1: resolution: {integrity: sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==} - sonner@1.3.1: - resolution: {integrity: sha512-+rOAO56b2eI3q5BtgljERSn2umRk63KFIvgb2ohbZ5X+Eb5u+a/7/0ZgswYqgBMg8dyl7n6OXd9KasA8QF9ToA==} - peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 - sonner@1.5.0: resolution: {integrity: sha512-FBjhG/gnnbN6FY0jaNnqZOMmB73R+5IiyYAw8yBj7L54ER7HB3fOSE5OFiQiE2iXWxeXKvg6fIP4LtVppHEdJA==} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - source-map-js@1.0.2: - resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} - engines: {node: '>=0.10.0'} - source-map-js@1.2.0: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} @@ -7745,9 +7408,6 @@ packages: tailwind-merge@1.14.0: resolution: {integrity: sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==} - tailwind-merge@2.2.0: - resolution: {integrity: sha512-SqqhhaL0T06SW59+JVNfAqKdqLs0497esifRrZ7jOaefP3o64fdFNDMrAQWZFMxTLJPiHVjRLUywT8uFz1xNWQ==} - tailwind-merge@2.4.0: resolution: {integrity: sha512-49AwoOQNKdqKPd9CViyH5wJoSKsCDjUlzL8DxuGp3P1FsGY36NJDAa18jLZcaHAUUuTj+JB8IAo8zWgBNvBF7A==} @@ -7756,11 +7416,6 @@ packages: peerDependencies: tailwindcss: '>=3.0.0 || insiders' - tailwindcss@3.4.0: - resolution: {integrity: sha512-VigzymniH77knD1dryXbyxR+ePHihHociZbXnLZHUyzf2MMs2ZVqlUrZ3FvpXP8pno9JzmILt1sZPD19M3IxtA==} - engines: {node: '>=14.0.0'} - hasBin: true - tailwindcss@3.4.3: resolution: {integrity: sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==} engines: {node: '>=14.0.0'} @@ -7798,9 +7453,6 @@ packages: engines: {node: '>=10'} hasBin: true - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -7889,10 +7541,6 @@ packages: engines: {node: '>=18.0.0'} hasBin: true - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} @@ -7917,11 +7565,6 @@ packages: resolution: {integrity: sha512-+suCYpfJLAe4OXS6+PPXjW3urOS4IoP9waSiLuXfLgqZODKw/aWwASvzqE886wA0kQgGy0mIWyhd87VpqIy6Xg==} engines: {node: '>=16'} - typescript@5.1.6: - resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} - engines: {node: '>=14.17'} - hasBin: true - typescript@5.4.5: resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} engines: {node: '>=14.17'} @@ -8273,10 +7916,6 @@ packages: wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -8320,10 +7959,6 @@ packages: utf-8-validate: optional: true - xmlhttprequest-ssl@2.0.0: - resolution: {integrity: sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==} - engines: {node: '>=0.4.0'} - xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -8575,7 +8210,7 @@ snapshots: '@aws-sdk/client-sso-oidc': 3.577.0(@aws-sdk/client-sts@3.577.0) '@aws-sdk/client-sts': 3.577.0 '@aws-sdk/core': 3.576.0 - '@aws-sdk/credential-provider-node': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0) + '@aws-sdk/credential-provider-node': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0)(@aws-sdk/client-sts@3.577.0) '@aws-sdk/middleware-bucket-endpoint': 3.577.0 '@aws-sdk/middleware-expect-continue': 3.577.0 '@aws-sdk/middleware-flexible-checksums': 3.577.0 @@ -8636,7 +8271,7 @@ snapshots: '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sts': 3.577.0 '@aws-sdk/core': 3.576.0 - '@aws-sdk/credential-provider-node': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0) + '@aws-sdk/credential-provider-node': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0)(@aws-sdk/client-sts@3.577.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -8725,7 +8360,7 @@ snapshots: '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.577.0(@aws-sdk/client-sts@3.577.0) '@aws-sdk/core': 3.576.0 - '@aws-sdk/credential-provider-node': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0) + '@aws-sdk/credential-provider-node': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0)(@aws-sdk/client-sts@3.577.0) '@aws-sdk/middleware-host-header': 3.577.0 '@aws-sdk/middleware-logger': 3.577.0 '@aws-sdk/middleware-recursion-detection': 3.577.0 @@ -8793,12 +8428,12 @@ snapshots: '@smithy/util-stream': 3.0.1 tslib: 2.6.2 - '@aws-sdk/credential-provider-ini@3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0)': + '@aws-sdk/credential-provider-ini@3.577.0(@aws-sdk/client-sso-oidc@3.577.0)(@aws-sdk/client-sts@3.577.0)': dependencies: '@aws-sdk/client-sts': 3.577.0 '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0)) + '@aws-sdk/credential-provider-sso': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0) '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.577.0) '@aws-sdk/types': 3.577.0 '@smithy/credential-provider-imds': 3.0.0 @@ -8810,13 +8445,13 @@ snapshots: - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-node@3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0)': + '@aws-sdk/credential-provider-node@3.577.0(@aws-sdk/client-sso-oidc@3.577.0)(@aws-sdk/client-sts@3.577.0)': dependencies: '@aws-sdk/credential-provider-env': 3.577.0 '@aws-sdk/credential-provider-http': 3.577.0 - '@aws-sdk/credential-provider-ini': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))(@aws-sdk/client-sts@3.577.0) + '@aws-sdk/credential-provider-ini': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0)(@aws-sdk/client-sts@3.577.0) '@aws-sdk/credential-provider-process': 3.577.0 - '@aws-sdk/credential-provider-sso': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0)) + '@aws-sdk/credential-provider-sso': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0) '@aws-sdk/credential-provider-web-identity': 3.577.0(@aws-sdk/client-sts@3.577.0) '@aws-sdk/types': 3.577.0 '@smithy/credential-provider-imds': 3.0.0 @@ -8837,10 +8472,10 @@ snapshots: '@smithy/types': 3.0.0 tslib: 2.6.2 - '@aws-sdk/credential-provider-sso@3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))': + '@aws-sdk/credential-provider-sso@3.577.0(@aws-sdk/client-sso-oidc@3.577.0)': dependencies: '@aws-sdk/client-sso': 3.577.0 - '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0)) + '@aws-sdk/token-providers': 3.577.0(@aws-sdk/client-sso-oidc@3.577.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.0.0 '@smithy/shared-ini-file-loader': 3.0.0 @@ -8977,7 +8612,7 @@ snapshots: '@smithy/types': 3.0.0 tslib: 2.6.2 - '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.577.0(@aws-sdk/client-sts@3.577.0))': + '@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.577.0)': dependencies: '@aws-sdk/client-sso-oidc': 3.577.0(@aws-sdk/client-sts@3.577.0) '@aws-sdk/types': 3.577.0 @@ -9410,14 +9045,6 @@ snapshots: tslib: 2.6.2 optional: true - '@emotion/is-prop-valid@0.8.8': - dependencies: - '@emotion/memoize': 0.7.4 - optional: true - - '@emotion/memoize@0.7.4': - optional: true - '@ericcornelissen/bash-parser@0.5.2': dependencies: array-last: 1.3.0 @@ -9647,39 +9274,6 @@ snapshots: '@esbuild/win32-x64@0.21.5': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@9.8.0)': - dependencies: - eslint: 9.8.0 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.11.0': {} - - '@eslint/config-array@0.17.1': - dependencies: - '@eslint/object-schema': 2.1.4 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@eslint/eslintrc@3.1.0': - dependencies: - ajv: 6.12.6 - debug: 4.3.4 - espree: 10.1.0 - globals: 14.0.0 - ignore: 5.3.1 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.8.0': {} - - '@eslint/object-schema@2.1.4': {} - '@faker-js/faker@8.4.1': {} '@floating-ui/core@1.6.2': @@ -9783,10 +9377,6 @@ snapshots: dependencies: react-hook-form: 7.52.1(react@18.3.1) - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.3.0': {} - '@img/sharp-darwin-arm64@0.33.4': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.0.2 @@ -10011,59 +9601,59 @@ snapshots: - bufferutil - utf-8-validate - '@next/env@14.1.4': {} + '@next/env@14.2.3': {} '@next/env@14.2.4': {} - '@next/swc-darwin-arm64@14.1.4': + '@next/swc-darwin-arm64@14.2.3': optional: true '@next/swc-darwin-arm64@14.2.4': optional: true - '@next/swc-darwin-x64@14.1.4': + '@next/swc-darwin-x64@14.2.3': optional: true '@next/swc-darwin-x64@14.2.4': optional: true - '@next/swc-linux-arm64-gnu@14.1.4': + '@next/swc-linux-arm64-gnu@14.2.3': optional: true '@next/swc-linux-arm64-gnu@14.2.4': optional: true - '@next/swc-linux-arm64-musl@14.1.4': + '@next/swc-linux-arm64-musl@14.2.3': optional: true '@next/swc-linux-arm64-musl@14.2.4': optional: true - '@next/swc-linux-x64-gnu@14.1.4': + '@next/swc-linux-x64-gnu@14.2.3': optional: true '@next/swc-linux-x64-gnu@14.2.4': optional: true - '@next/swc-linux-x64-musl@14.1.4': + '@next/swc-linux-x64-musl@14.2.3': optional: true '@next/swc-linux-x64-musl@14.2.4': optional: true - '@next/swc-win32-arm64-msvc@14.1.4': + '@next/swc-win32-arm64-msvc@14.2.3': optional: true '@next/swc-win32-arm64-msvc@14.2.4': optional: true - '@next/swc-win32-ia32-msvc@14.1.4': + '@next/swc-win32-ia32-msvc@14.2.3': optional: true '@next/swc-win32-ia32-msvc@14.2.4': optional: true - '@next/swc-win32-x64-msvc@14.1.4': + '@next/swc-win32-x64-msvc@14.2.3': optional: true '@next/swc-win32-x64-msvc@14.2.4': @@ -10408,8 +9998,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@radix-ui/colors@1.0.1': {} - '@radix-ui/number@1.0.1': dependencies: '@babel/runtime': 7.24.5 @@ -10464,15 +10052,6 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-arrow@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@radix-ui/react-arrow@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) @@ -10510,23 +10089,7 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-collapsible@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-id': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - - '@radix-ui/react-collapsible@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-collapsible@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -10555,18 +10118,6 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-collection@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@radix-ui/react-collection@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -10586,12 +10137,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@radix-ui/react-compose-refs@1.1.0(@types/react@18.2.47)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.2.47 - '@radix-ui/react-compose-refs@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: react: 18.3.1 @@ -10605,12 +10150,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@radix-ui/react-context@1.1.0(@types/react@18.2.47)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.2.47 - '@radix-ui/react-context@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: react: 18.3.1 @@ -10647,12 +10186,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@radix-ui/react-direction@1.1.0(@types/react@18.2.47)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.2.47 - '@radix-ui/react-direction@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: react: 18.3.1 @@ -10673,19 +10206,6 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 @@ -10722,12 +10242,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@radix-ui/react-focus-guards@1.1.0(@types/react@18.2.47)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.2.47 - '@radix-ui/react-focus-guards@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: react: 18.3.1 @@ -10746,17 +10260,6 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-focus-scope@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@radix-ui/react-focus-scope@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -10776,13 +10279,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@radix-ui/react-id@1.1.0(@types/react@18.2.47)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.2.47 - '@radix-ui/react-id@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -10827,29 +10323,6 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-popover@1.1.1(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.47)(react@18.3.1) - aria-hidden: 1.2.4 - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - react-remove-scroll: 2.5.7(@types/react@18.2.47)(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@radix-ui/react-popover@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 @@ -10892,24 +10365,6 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-popper@1.2.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@floating-ui/react-dom': 2.0.9(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-arrow': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-use-rect': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/rect': 1.1.0 - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@radix-ui/react-popper@1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@floating-ui/react-dom': 2.0.9(react-dom@18.2.0(react@18.3.1))(react@18.3.1) @@ -10938,16 +10393,6 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-portal@1.1.1(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@radix-ui/react-portal@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) @@ -10969,16 +10414,6 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-presence@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@radix-ui/react-presence@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -10999,15 +10434,6 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-primitive@2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-slot': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@radix-ui/react-primitive@2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -11053,23 +10479,6 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-roving-focus@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-direction': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-id': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@radix-ui/react-roving-focus@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 @@ -11152,13 +10561,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@radix-ui/react-slot@1.1.0(@types/react@18.2.47)(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.2.47 - '@radix-ui/react-slot@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -11215,21 +10617,6 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-toggle-group@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-context': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-direction': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@radix-ui/react-toggle@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.24.5 @@ -11242,17 +10629,6 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-toggle@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@radix-ui/react-toolbar@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.24.5 @@ -11269,26 +10645,6 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-tooltip@1.1.1(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@radix-ui/react-tooltip@1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 @@ -11316,12 +10672,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.2.47)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.2.47 - '@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: react: 18.3.1 @@ -11336,13 +10686,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.2.47)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.2.47 - '@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -11358,13 +10701,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.2.47)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.2.47 - '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -11379,12 +10715,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.2.47)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.2.47 - '@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: react: 18.3.1 @@ -11412,13 +10742,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@radix-ui/react-use-rect@1.1.0(@types/react@18.2.47)(react@18.3.1)': - dependencies: - '@radix-ui/rect': 1.1.0 - react: 18.3.1 - optionalDependencies: - '@types/react': 18.2.47 - '@radix-ui/react-use-rect@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: '@radix-ui/rect': 1.1.0 @@ -11434,13 +10757,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@radix-ui/react-use-size@1.1.0(@types/react@18.2.47)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.47)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.2.47 - '@radix-ui/react-use-size@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -11458,15 +10774,6 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 - '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) @@ -11482,99 +10789,95 @@ snapshots: '@radix-ui/rect@1.1.0': {} - '@react-email/body@0.0.9(react@18.3.1)': + '@react-email/body@0.0.10(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/button@0.0.16(react@18.3.1)': + '@react-email/button@0.0.17(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/code-block@0.0.6(react@18.3.1)': + '@react-email/code-block@0.0.9(react@18.3.1)': dependencies: prismjs: 1.29.0 react: 18.3.1 - '@react-email/code-inline@0.0.3(react@18.3.1)': + '@react-email/code-inline@0.0.4(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/column@0.0.11(react@18.3.1)': + '@react-email/column@0.0.12(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/components@0.0.22(@types/react@18.3.3)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-email/body': 0.0.9(react@18.3.1) - '@react-email/button': 0.0.16(react@18.3.1) - '@react-email/code-block': 0.0.6(react@18.3.1) - '@react-email/code-inline': 0.0.3(react@18.3.1) - '@react-email/column': 0.0.11(react@18.3.1) - '@react-email/container': 0.0.13(react@18.3.1) - '@react-email/font': 0.0.7(react@18.3.1) - '@react-email/head': 0.0.10(react@18.3.1) - '@react-email/heading': 0.0.13(@types/react@18.3.3)(react@18.3.1) - '@react-email/hr': 0.0.9(react@18.3.1) - '@react-email/html': 0.0.9(react@18.3.1) - '@react-email/img': 0.0.9(react@18.3.1) - '@react-email/link': 0.0.9(react@18.3.1) - '@react-email/markdown': 0.0.11(react@18.3.1) - '@react-email/preview': 0.0.10(react@18.3.1) - '@react-email/render': 0.0.17(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@react-email/row': 0.0.9(react@18.3.1) - '@react-email/section': 0.0.13(react@18.3.1) - '@react-email/tailwind': 0.0.19(react@18.3.1) - '@react-email/text': 0.0.9(react@18.3.1) + '@react-email/components@0.0.25(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': + dependencies: + '@react-email/body': 0.0.10(react@18.3.1) + '@react-email/button': 0.0.17(react@18.3.1) + '@react-email/code-block': 0.0.9(react@18.3.1) + '@react-email/code-inline': 0.0.4(react@18.3.1) + '@react-email/column': 0.0.12(react@18.3.1) + '@react-email/container': 0.0.14(react@18.3.1) + '@react-email/font': 0.0.8(react@18.3.1) + '@react-email/head': 0.0.11(react@18.3.1) + '@react-email/heading': 0.0.14(react@18.3.1) + '@react-email/hr': 0.0.10(react@18.3.1) + '@react-email/html': 0.0.10(react@18.3.1) + '@react-email/img': 0.0.10(react@18.3.1) + '@react-email/link': 0.0.10(react@18.3.1) + '@react-email/markdown': 0.0.12(react@18.3.1) + '@react-email/preview': 0.0.11(react@18.3.1) + '@react-email/render': 1.0.1(react-dom@18.2.0(react@18.3.1))(react@18.3.1) + '@react-email/row': 0.0.10(react@18.3.1) + '@react-email/section': 0.0.14(react@18.3.1) + '@react-email/tailwind': 0.1.0(react@18.3.1) + '@react-email/text': 0.0.10(react@18.3.1) react: 18.3.1 transitivePeerDependencies: - - '@types/react' - react-dom - '@react-email/container@0.0.13(react@18.3.1)': + '@react-email/container@0.0.14(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/font@0.0.7(react@18.3.1)': + '@react-email/font@0.0.8(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/head@0.0.10(react@18.3.1)': + '@react-email/head@0.0.11(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/heading@0.0.13(@types/react@18.3.3)(react@18.3.1)': + '@react-email/heading@0.0.14(react@18.3.1)': dependencies: - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@18.3.1) react: 18.3.1 - transitivePeerDependencies: - - '@types/react' - '@react-email/hr@0.0.9(react@18.3.1)': + '@react-email/hr@0.0.10(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/html@0.0.9(react@18.3.1)': + '@react-email/html@0.0.10(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/img@0.0.9(react@18.3.1)': + '@react-email/img@0.0.10(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/link@0.0.9(react@18.3.1)': + '@react-email/link@0.0.10(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/markdown@0.0.11(react@18.3.1)': + '@react-email/markdown@0.0.12(react@18.3.1)': dependencies: md-to-react-email: 5.0.2(react@18.3.1) react: 18.3.1 - '@react-email/preview@0.0.10(react@18.3.1)': + '@react-email/preview@0.0.11(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/render@0.0.17(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': + '@react-email/render@1.0.1(react-dom@18.2.0(react@18.3.1))(react@18.3.1)': dependencies: html-to-text: 9.0.5 js-beautify: 1.15.1 @@ -11582,19 +10885,19 @@ snapshots: react-dom: 18.2.0(react@18.3.1) react-promise-suspense: 0.3.4 - '@react-email/row@0.0.9(react@18.3.1)': + '@react-email/row@0.0.10(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/section@0.0.13(react@18.3.1)': + '@react-email/section@0.0.14(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/tailwind@0.0.19(react@18.3.1)': + '@react-email/tailwind@0.1.0(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/text@0.0.9(react@18.3.1)': + '@react-email/text@0.0.10(react@18.3.1)': dependencies: react: 18.3.1 @@ -12201,7 +11504,7 @@ snapshots: rollup: 3.29.4 stacktrace-parser: 0.1.10 optionalDependencies: - webpack: 5.92.0(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11) + webpack: 5.92.0 transitivePeerDependencies: - '@opentelemetry/api' - '@opentelemetry/core' @@ -12282,7 +11585,7 @@ snapshots: '@sentry/bundler-plugin-core': 2.20.1 unplugin: 1.0.1 uuid: 9.0.1 - webpack: 5.92.0(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11) + webpack: 5.92.0 transitivePeerDependencies: - encoding - supports-color @@ -12717,53 +12020,6 @@ snapshots: '@stripe/stripe-js@4.1.0': {} - '@swc/core-darwin-arm64@1.3.101': - optional: true - - '@swc/core-darwin-x64@1.3.101': - optional: true - - '@swc/core-linux-arm-gnueabihf@1.3.101': - optional: true - - '@swc/core-linux-arm64-gnu@1.3.101': - optional: true - - '@swc/core-linux-arm64-musl@1.3.101': - optional: true - - '@swc/core-linux-x64-gnu@1.3.101': - optional: true - - '@swc/core-linux-x64-musl@1.3.101': - optional: true - - '@swc/core-win32-arm64-msvc@1.3.101': - optional: true - - '@swc/core-win32-ia32-msvc@1.3.101': - optional: true - - '@swc/core-win32-x64-msvc@1.3.101': - optional: true - - '@swc/core@1.3.101(@swc/helpers@0.5.11)': - dependencies: - '@swc/counter': 0.1.3 - '@swc/types': 0.1.12 - optionalDependencies: - '@swc/core-darwin-arm64': 1.3.101 - '@swc/core-darwin-x64': 1.3.101 - '@swc/core-linux-arm-gnueabihf': 1.3.101 - '@swc/core-linux-arm64-gnu': 1.3.101 - '@swc/core-linux-arm64-musl': 1.3.101 - '@swc/core-linux-x64-gnu': 1.3.101 - '@swc/core-linux-x64-musl': 1.3.101 - '@swc/core-win32-arm64-msvc': 1.3.101 - '@swc/core-win32-ia32-msvc': 1.3.101 - '@swc/core-win32-x64-msvc': 1.3.101 - '@swc/helpers': 0.5.11 - '@swc/counter@0.1.3': {} '@swc/helpers@0.4.14': @@ -12779,19 +12035,11 @@ snapshots: dependencies: tslib: 2.6.2 - '@swc/helpers@0.5.2': - dependencies: - tslib: 2.6.2 - '@swc/helpers@0.5.5': dependencies: '@swc/counter': 0.1.3 tslib: 2.6.2 - '@swc/types@0.1.12': - dependencies: - '@swc/counter': 0.1.3 - '@t3-oss/env-core@0.10.1(typescript@5.4.5)(zod@3.23.8)': dependencies: zod: 3.23.8 @@ -13186,8 +12434,6 @@ snapshots: pg-protocol: 1.6.1 pg-types: 2.2.0 - '@types/prismjs@1.26.4': {} - '@types/prop-types@15.7.12': {} '@types/qs@6.9.15': {} @@ -13198,19 +12444,11 @@ snapshots: dependencies: '@types/react': 18.3.3 - '@types/react@18.2.47': - dependencies: - '@types/prop-types': 15.7.12 - '@types/scheduler': 0.23.0 - csstype: 3.1.3 - '@types/react@18.3.3': dependencies: '@types/prop-types': 15.7.12 csstype: 3.1.3 - '@types/scheduler@0.23.0': {} - '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 @@ -13236,17 +12474,6 @@ snapshots: '@types/web-bluetooth@0.0.20': {} - '@types/webpack@5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11)': - dependencies: - '@types/node': 20.12.12 - tapable: 2.2.1 - webpack: 5.92.0(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11) - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - webpack-cli - '@uiw/codemirror-themes@4.22.2(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.28.2)': dependencies: '@codemirror/language': 6.10.2 @@ -13949,7 +13176,7 @@ snapshots: dependencies: acorn: 8.11.3 - acorn-jsx@5.3.2(acorn@8.12.1): + acorn-import-attributes@1.9.5(acorn@8.12.1): dependencies: acorn: 8.12.1 @@ -14068,16 +13295,6 @@ snapshots: attr-accept@2.2.2: {} - autoprefixer@10.4.14(postcss@8.4.38): - dependencies: - browserslist: 4.23.0 - caniuse-lite: 1.0.30001620 - fraction.js: 4.3.7 - normalize-range: 0.1.2 - picocolors: 1.0.1 - postcss: 8.4.38 - postcss-value-parser: 4.2.0 - autoprefixer@10.4.19(postcss@8.4.40): dependencies: browserslist: 4.23.0 @@ -14180,8 +13397,6 @@ snapshots: get-intrinsic: 1.2.4 set-function-length: 1.2.2 - callsites@3.1.0: {} - camelcase-css@2.0.1: {} caniuse-lite@1.0.30001620: {} @@ -14238,18 +13453,6 @@ snapshots: dependencies: get-func-name: 2.0.2 - chokidar@3.5.3: - dependencies: - anymatch: 3.1.3 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -14304,8 +13507,6 @@ snapshots: clone@2.1.2: {} - clsx@1.2.1: {} - clsx@2.0.0: {} clsx@2.1.0: {} @@ -14521,8 +13722,6 @@ snapshots: deep-freeze@0.0.1: {} - deep-is@0.1.4: {} - deepmerge@4.3.1: {} defaults@1.0.4: @@ -14537,8 +13736,6 @@ snapshots: defu@6.1.4: {} - delay@5.0.0: {} - delayed-stream@1.0.0: {} delegates@1.0.0: @@ -14591,8 +13788,6 @@ snapshots: domelementtype: 2.3.0 domhandler: 5.0.3 - dotenv@16.0.3: {} - dotenv@16.4.5: {} duplexer@0.1.2: {} @@ -14628,18 +13823,6 @@ snapshots: dependencies: once: 1.4.0 - engine.io-client@6.5.4: - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.3.4 - engine.io-parser: 5.2.3 - ws: 8.17.1 - xmlhttprequest-ssl: 2.0.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - engine.io-parser@5.2.3: {} engine.io@6.5.5: @@ -14760,83 +13943,11 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-prettier@9.0.0(eslint@9.8.0): - dependencies: - eslint: 9.8.0 - - eslint-config-turbo@1.10.12(eslint@9.8.0): - dependencies: - eslint: 9.8.0 - eslint-plugin-turbo: 1.10.12(eslint@9.8.0) - - eslint-plugin-turbo@1.10.12(eslint@9.8.0): - dependencies: - dotenv: 16.0.3 - eslint: 9.8.0 - eslint-scope@5.1.1: dependencies: esrecurse: 4.3.0 estraverse: 4.3.0 - eslint-scope@8.0.2: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.0.0: {} - - eslint@9.8.0: - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.8.0) - '@eslint-community/regexpp': 4.11.0 - '@eslint/config-array': 0.17.1 - '@eslint/eslintrc': 3.1.0 - '@eslint/js': 9.8.0 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.3.0 - '@nodelib/fs.walk': 1.2.8 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 - escape-string-regexp: 4.0.0 - eslint-scope: 8.0.2 - eslint-visitor-keys: 4.0.0 - espree: 10.1.0 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.1 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - - espree@10.1.0: - dependencies: - acorn: 8.12.1 - acorn-jsx: 5.3.2(acorn@8.12.1) - eslint-visitor-keys: 4.0.0 - - esquery@1.6.0: - dependencies: - estraverse: 5.3.0 - esrecurse@4.3.0: dependencies: estraverse: 5.3.0 @@ -14851,8 +13962,6 @@ snapshots: dependencies: '@types/estree': 1.0.5 - esutils@2.0.3: {} - event-target-shim@5.0.1: {} eventemitter3@4.0.7: {} @@ -14899,8 +14008,6 @@ snapshots: fast-json-stable-stringify@2.1.0: {} - fast-levenshtein@2.0.6: {} - fast-redact@3.5.0: {} fast-safe-stringify@2.1.1: {} @@ -14990,14 +14097,6 @@ snapshots: fraction.js@4.3.7: {} - framer-motion@10.17.4(react-dom@18.2.0(react@18.3.1))(react@18.3.1): - dependencies: - tslib: 2.6.2 - optionalDependencies: - '@emotion/is-prop-valid': 0.8.8 - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - fs-extra@11.1.1: dependencies: graceful-fs: 4.2.11 @@ -15069,14 +14168,6 @@ snapshots: glob-to-regexp@0.4.1: {} - glob@10.3.15: - dependencies: - foreground-child: 3.1.1 - jackspeak: 2.3.6 - minimatch: 9.0.4 - minipass: 7.1.1 - path-scurry: 1.11.1 - glob@10.3.4: dependencies: foreground-child: 3.1.1 @@ -15113,8 +14204,6 @@ snapshots: globals@11.12.0: {} - globals@14.0.0: {} - gopd@1.0.1: dependencies: get-intrinsic: 1.2.4 @@ -15457,11 +14546,6 @@ snapshots: ignore@5.3.1: {} - import-fresh@3.3.0: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - import-in-the-middle@1.7.1: dependencies: acorn: 8.11.3 @@ -15477,8 +14561,6 @@ snapshots: cjs-module-lexer: 1.3.1 module-details-from-path: 1.0.3 - imurmurhash@0.1.4: {} - indent-string@4.0.0: {} inflight@1.0.6: @@ -15571,8 +14653,6 @@ snapshots: is-obj@1.0.1: {} - is-path-inside@3.0.3: {} - is-plain-obj@4.1.0: {} is-plain-object@5.0.0: {} @@ -15666,8 +14746,6 @@ snapshots: json-schema-traverse@1.0.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} - json5@2.2.3: {} jsonfile@6.1.0: @@ -15715,11 +14793,6 @@ snapshots: leven@4.0.0: {} - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - lib0@0.2.94: dependencies: isomorphic.js: 0.2.5 @@ -16543,8 +15616,6 @@ snapshots: minipass@5.0.0: optional: true - minipass@7.1.1: {} - minipass@7.1.2: {} minizlib@2.1.2: @@ -16588,8 +15659,6 @@ snapshots: nanoid@5.0.7: {} - natural-compare@1.4.0: {} - negotiator@0.6.3: {} neo-async@2.6.2: {} @@ -16615,10 +15684,10 @@ snapshots: dependencies: nprogress: 0.2.0 - next@14.1.4(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.3.1))(react@18.3.1): + next@14.2.3(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.3.1))(react@18.3.1): dependencies: - '@next/env': 14.1.4 - '@swc/helpers': 0.5.2 + '@next/env': 14.2.3 + '@swc/helpers': 0.5.5 busboy: 1.6.0 caniuse-lite: 1.0.30001620 graceful-fs: 4.2.11 @@ -16627,15 +15696,15 @@ snapshots: react-dom: 18.2.0(react@18.3.1) styled-jsx: 5.1.1(@babel/core@7.24.5)(react@18.3.1) optionalDependencies: - '@next/swc-darwin-arm64': 14.1.4 - '@next/swc-darwin-x64': 14.1.4 - '@next/swc-linux-arm64-gnu': 14.1.4 - '@next/swc-linux-arm64-musl': 14.1.4 - '@next/swc-linux-x64-gnu': 14.1.4 - '@next/swc-linux-x64-musl': 14.1.4 - '@next/swc-win32-arm64-msvc': 14.1.4 - '@next/swc-win32-ia32-msvc': 14.1.4 - '@next/swc-win32-x64-msvc': 14.1.4 + '@next/swc-darwin-arm64': 14.2.3 + '@next/swc-darwin-x64': 14.2.3 + '@next/swc-linux-arm64-gnu': 14.2.3 + '@next/swc-linux-arm64-musl': 14.2.3 + '@next/swc-linux-x64-gnu': 14.2.3 + '@next/swc-linux-x64-musl': 14.2.3 + '@next/swc-win32-arm64-msvc': 14.2.3 + '@next/swc-win32-ia32-msvc': 14.2.3 + '@next/swc-win32-x64-msvc': 14.2.3 '@opentelemetry/api': 1.9.0 transitivePeerDependencies: - '@babel/core' @@ -16760,15 +15829,6 @@ snapshots: - supports-color optional: true - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - ora@5.4.1: dependencies: bl: 4.1.0 @@ -16809,10 +15869,6 @@ snapshots: papaparse@5.4.1: {} - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - parse-ms@3.0.0: {} parse-ms@4.0.0: {} @@ -16870,15 +15926,11 @@ snapshots: peberminta@0.9.0: {} - pg-boss@9.0.3: + pg-boss@10.1.1: dependencies: cron-parser: 4.9.0 - delay: 5.0.0 - lodash.debounce: 4.0.8 - p-map: 4.0.0 pg: 8.11.5 serialize-error: 8.1.0 - uuid: 9.0.1 transitivePeerDependencies: - pg-native @@ -17019,12 +16071,6 @@ snapshots: picocolors: 1.0.1 source-map-js: 1.2.0 - postcss@8.4.38: - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 - postcss@8.4.40: dependencies: nanoid: 3.3.7 @@ -17048,8 +16094,6 @@ snapshots: preact@10.22.0: {} - prelude-ls@1.2.1: {} - pretty-bytes@6.1.1: {} pretty-format@27.5.1: @@ -17074,12 +16118,6 @@ snapshots: dependencies: parse-ms: 4.0.0 - prism-react-renderer@2.1.0(react@18.3.1): - dependencies: - '@types/prismjs': 1.26.4 - clsx: 1.2.1 - react: 18.3.1 - prisma-extension-pagination@0.7.4(@prisma/client@5.14.0(prisma@5.14.0)): dependencies: '@prisma/client': 5.14.0(prisma@5.14.0) @@ -17294,60 +16332,32 @@ snapshots: prop-types: 15.8.1 react: 18.3.1 - react-email@2.1.6(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.11)(eslint@9.8.0): + react-email@3.0.1(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.3.1))(react@18.3.1): dependencies: '@babel/core': 7.24.5 '@babel/parser': 7.24.5 - '@radix-ui/colors': 1.0.1 - '@radix-ui/react-collapsible': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-popover': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.1.0(@types/react@18.2.47)(react@18.3.1) - '@radix-ui/react-toggle-group': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@radix-ui/react-tooltip': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.2.47)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - '@swc/core': 1.3.101(@swc/helpers@0.5.11) - '@types/react': 18.2.47 - '@types/react-dom': 18.3.0 - '@types/webpack': 5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11) - autoprefixer: 10.4.14(postcss@8.4.38) chalk: 4.1.2 - chokidar: 3.5.3 - clsx: 2.1.0 + chokidar: 3.6.0 commander: 11.1.0 debounce: 2.0.0 esbuild: 0.19.11 - eslint-config-prettier: 9.0.0(eslint@9.8.0) - eslint-config-turbo: 1.10.12(eslint@9.8.0) - framer-motion: 10.17.4(react-dom@18.2.0(react@18.3.1))(react@18.3.1) glob: 10.3.4 log-symbols: 4.1.0 mime-types: 2.1.35 - next: 14.1.4(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) + next: 14.2.3(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.3.1))(react@18.3.1) normalize-path: 3.0.0 ora: 5.4.1 - postcss: 8.4.38 - prism-react-renderer: 2.1.0(react@18.3.1) - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - socket.io: 4.7.3 - socket.io-client: 4.7.3 - sonner: 1.3.1(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - source-map-js: 1.0.2 - stacktrace-parser: 0.1.10 - tailwind-merge: 2.2.0 - tailwindcss: 3.4.0 - typescript: 5.1.6 + socket.io: 4.7.5 transitivePeerDependencies: - '@opentelemetry/api' - - '@swc/helpers' + - '@playwright/test' - babel-plugin-macros - bufferutil - - eslint + - react + - react-dom - sass - supports-color - - ts-node - - uglify-js - utf-8-validate - - webpack-cli react-hook-form@7.52.1(react@18.3.1): dependencies: @@ -17391,14 +16401,6 @@ snapshots: dependencies: fast-deep-equal: 2.0.1 - react-remove-scroll-bar@2.3.6(@types/react@18.2.47)(react@18.3.1): - dependencies: - react: 18.3.1 - react-style-singleton: 2.2.1(@types/react@18.2.47)(react@18.3.1) - tslib: 2.6.2 - optionalDependencies: - '@types/react': 18.2.47 - react-remove-scroll-bar@2.3.6(@types/react@18.3.3)(react@18.3.1): dependencies: react: 18.3.1 @@ -17429,17 +16431,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - react-remove-scroll@2.5.7(@types/react@18.2.47)(react@18.3.1): - dependencies: - react: 18.3.1 - react-remove-scroll-bar: 2.3.6(@types/react@18.2.47)(react@18.3.1) - react-style-singleton: 2.2.1(@types/react@18.2.47)(react@18.3.1) - tslib: 2.6.2 - use-callback-ref: 1.3.2(@types/react@18.2.47)(react@18.3.1) - use-sidecar: 1.1.2(@types/react@18.2.47)(react@18.3.1) - optionalDependencies: - '@types/react': 18.2.47 - react-remove-scroll@2.5.7(@types/react@18.3.3)(react@18.3.1): dependencies: react: 18.3.1 @@ -17459,15 +16450,6 @@ snapshots: react-dom: 18.2.0(react@18.3.1) react-transition-group: 4.4.5(react-dom@18.2.0(react@18.3.1))(react@18.3.1) - react-style-singleton@2.2.1(@types/react@18.2.47)(react@18.3.1): - dependencies: - get-nonce: 1.0.1 - invariant: 2.2.4 - react: 18.3.1 - tslib: 2.6.2 - optionalDependencies: - '@types/react': 18.2.47 - react-style-singleton@2.2.1(@types/react@18.3.3)(react@18.3.1): dependencies: get-nonce: 1.0.1 @@ -17716,8 +16698,6 @@ snapshots: transitivePeerDependencies: - supports-color - resolve-from@4.0.0: {} - resolve-pkg-maps@1.0.0: {} resolve@1.22.8: @@ -17934,17 +16914,6 @@ snapshots: - supports-color - utf-8-validate - socket.io-client@4.7.3: - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.3.4 - engine.io-client: 6.5.4 - socket.io-parser: 4.2.4 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - socket.io-parser@4.2.4: dependencies: '@socket.io/component-emitter': 3.1.2 @@ -17952,7 +16921,7 @@ snapshots: transitivePeerDependencies: - supports-color - socket.io@4.7.3: + socket.io@4.7.5: dependencies: accepts: 1.3.8 base64id: 2.0.0 @@ -17970,18 +16939,11 @@ snapshots: dependencies: atomic-sleep: 1.0.0 - sonner@1.3.1(react-dom@18.2.0(react@18.3.1))(react@18.3.1): - dependencies: - react: 18.3.1 - react-dom: 18.2.0(react@18.3.1) - sonner@1.5.0(react-dom@18.2.0(react@18.3.1))(react@18.3.1): dependencies: react: 18.3.1 react-dom: 18.2.0(react@18.3.1) - source-map-js@1.0.2: {} - source-map-js@1.2.0: {} source-map-support@0.5.21: @@ -18084,7 +17046,7 @@ snapshots: dependencies: '@jridgewell/gen-mapping': 0.3.5 commander: 4.1.1 - glob: 10.3.15 + glob: 10.4.5 lines-and-columns: 1.2.4 mz: 2.7.0 pirates: 4.0.6 @@ -18116,43 +17078,12 @@ snapshots: tailwind-merge@1.14.0: {} - tailwind-merge@2.2.0: - dependencies: - '@babel/runtime': 7.24.5 - tailwind-merge@2.4.0: {} tailwindcss-animate@1.0.7(tailwindcss@3.4.3): dependencies: tailwindcss: 3.4.3 - tailwindcss@3.4.0: - dependencies: - '@alloc/quick-lru': 5.2.0 - arg: 5.0.2 - chokidar: 3.6.0 - didyoumean: 1.2.2 - dlv: 1.1.3 - fast-glob: 3.3.2 - glob-parent: 6.0.2 - is-glob: 4.0.3 - jiti: 1.21.0 - lilconfig: 2.1.0 - micromatch: 4.0.5 - normalize-path: 3.0.0 - object-hash: 3.0.0 - picocolors: 1.0.1 - postcss: 8.4.40 - postcss-import: 15.1.0(postcss@8.4.40) - postcss-js: 4.0.1(postcss@8.4.40) - postcss-load-config: 4.0.2(postcss@8.4.40) - postcss-nested: 6.0.1(postcss@8.4.40) - postcss-selector-parser: 6.0.16 - resolve: 1.22.8 - sucrase: 3.35.0 - transitivePeerDependencies: - - ts-node - tailwindcss@3.4.3: dependencies: '@alloc/quick-lru': 5.2.0 @@ -18196,27 +17127,22 @@ snapshots: dependencies: memoizerific: 1.11.3 - terser-webpack-plugin@5.3.10(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11)(webpack@5.92.0): + terser-webpack-plugin@5.3.10(webpack@5.92.0): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.1 - webpack: 5.92.0(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11) - optionalDependencies: - '@swc/core': 1.3.101(@swc/helpers@0.5.11) - esbuild: 0.19.11 + webpack: 5.92.0 terser@5.31.1: dependencies: '@jridgewell/source-map': 0.3.6 - acorn: 8.11.3 + acorn: 8.12.1 commander: 2.20.3 source-map-support: 0.5.21 - text-table@0.2.0: {} - thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -18290,10 +17216,6 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - type-detect@4.0.8: {} type-fest@0.20.2: {} @@ -18306,8 +17228,6 @@ snapshots: type-fest@4.18.2: {} - typescript@5.1.6: {} - typescript@5.4.5: {} ua-parser-js@1.0.37: {} @@ -18436,13 +17356,6 @@ snapshots: dependencies: punycode: 2.3.1 - use-callback-ref@1.3.2(@types/react@18.2.47)(react@18.3.1): - dependencies: - react: 18.3.1 - tslib: 2.6.2 - optionalDependencies: - '@types/react': 18.2.47 - use-callback-ref@1.3.2(@types/react@18.3.3)(react@18.3.1): dependencies: react: 18.3.1 @@ -18471,14 +17384,6 @@ snapshots: dependencies: react: 18.3.1 - use-sidecar@1.1.2(@types/react@18.2.47)(react@18.3.1): - dependencies: - detect-node-es: 1.1.0 - react: 18.3.1 - tslib: 2.6.2 - optionalDependencies: - '@types/react': 18.2.47 - use-sidecar@1.1.2(@types/react@18.3.3)(react@18.3.1): dependencies: detect-node-es: 1.1.0 @@ -18702,15 +17607,15 @@ snapshots: webpack-virtual-modules@0.5.0: {} - webpack@5.92.0(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11): + webpack@5.92.0: dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.5 '@webassemblyjs/ast': 1.12.1 '@webassemblyjs/wasm-edit': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 - acorn: 8.11.3 - acorn-import-attributes: 1.9.5(acorn@8.11.3) + acorn: 8.12.1 + acorn-import-attributes: 1.9.5(acorn@8.12.1) browserslist: 4.23.0 chrome-trace-event: 1.0.4 enhanced-resolve: 5.17.0 @@ -18725,7 +17630,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.3.101(@swc/helpers@0.5.11))(esbuild@0.19.11)(webpack@5.92.0) + terser-webpack-plugin: 5.3.10(webpack@5.92.0) watchpack: 2.4.1 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -18760,8 +17665,6 @@ snapshots: string-width: 4.2.3 optional: true - word-wrap@1.2.5: {} - wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 @@ -18792,8 +17695,6 @@ snapshots: ws@8.17.1: {} - xmlhttprequest-ssl@2.0.0: {} - xtend@4.0.2: {} y-codemirror.next@0.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.28.2)(yjs@13.6.15): diff --git a/prisma/migrations/20240906132847_add_new_status/migration.sql b/prisma/migrations/20240906132847_add_new_status/migration.sql new file mode 100644 index 000000000..fe50e189f --- /dev/null +++ b/prisma/migrations/20240906132847_add_new_status/migration.sql @@ -0,0 +1,16 @@ +/* + Warnings: + + - The values [SENT,WAITING] on the enum `TemplateStatus` will be removed. If these variants are still used in the database, this will fail. + +*/ +-- AlterEnum +BEGIN; +CREATE TYPE "TemplateStatus_new" AS ENUM ('DRAFT', 'COMPLETE', 'PENDING', 'CANCELLED'); +ALTER TABLE "Template" ALTER COLUMN "status" DROP DEFAULT; +ALTER TABLE "Template" ALTER COLUMN "status" TYPE "TemplateStatus_new" USING ("status"::text::"TemplateStatus_new"); +ALTER TYPE "TemplateStatus" RENAME TO "TemplateStatus_old"; +ALTER TYPE "TemplateStatus_new" RENAME TO "TemplateStatus"; +DROP TYPE "TemplateStatus_old"; +ALTER TABLE "Template" ALTER COLUMN "status" SET DEFAULT 'DRAFT'; +COMMIT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 008d0c68f..7a2c88460 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -602,8 +602,7 @@ model TemplateField { enum TemplateStatus { DRAFT COMPLETE - SENT - WAITING + PENDING CANCELLED } diff --git a/src/app/(authenticated)/(dashboard)/[publicId]/documents/esign/v/[templatePublicId]/page.tsx b/src/app/(authenticated)/(dashboard)/[publicId]/documents/esign/v/[templatePublicId]/page.tsx index 648983984..c22b08356 100644 --- a/src/app/(authenticated)/(dashboard)/[publicId]/documents/esign/v/[templatePublicId]/page.tsx +++ b/src/app/(authenticated)/(dashboard)/[publicId]/documents/esign/v/[templatePublicId]/page.tsx @@ -3,6 +3,7 @@ import { Alert, AlertDescription } from "@/components/ui/alert"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { serverAccessControl } from "@/lib/rbac/access-control"; +import type { TemplateStatus } from "@/prisma/enums"; import { TemplateSigningFieldProvider } from "@/providers/template-signing-field-provider"; import { api } from "@/trpc/server"; import { RiCheckFill } from "@remixicon/react"; @@ -14,6 +15,13 @@ type BadgeVariant = | "secondary" | "destructive"; +const variantMap: Record = { + CANCELLED: "destructive", + COMPLETE: "success", + DRAFT: "info", + PENDING: "secondary", +}; + export default async function TemplateDetailViewPage({ params: { templatePublicId }, }: { @@ -36,29 +44,12 @@ export default async function TemplateDetailViewPage({ ), ]); - const badgeVariant = (): BadgeVariant => { - let result: BadgeVariant = "warning"; - - if (status === "DRAFT") { - result = "warning"; - } else if (status === "SENT") { - result = "info"; - } else if (status === "COMPLETE") { - result = "success"; - } else if (status === "WAITING") { - result = "secondary"; - } else if (status === "CANCELLED") { - result = "destructive"; - } - return result; - }; - return (
- + {status} diff --git a/src/app/updates/[publicId]/page.tsx b/src/app/updates/[publicId]/page.tsx index 61a8e9f06..ce6fb30f4 100644 --- a/src/app/updates/[publicId]/page.tsx +++ b/src/app/updates/[publicId]/page.tsx @@ -7,7 +7,7 @@ import UpdateRenderer from "@/components/update/renderer"; import { type JWTVerifyResult, decode } from "@/lib/jwt"; import { UpdateStatusEnum } from "@/prisma/enums"; import { db } from "@/server/db"; -import { renderAsync } from "@react-email/components"; +import { render } from "@react-email/components"; import { RiLock2Line } from "@remixicon/react"; import { notFound } from "next/navigation"; import { Fragment } from "react"; @@ -100,7 +100,7 @@ const PublicUpdatePage = async ({ const company = update?.company; const author = update?.author; - const html = await renderAsync(); + const html = await render(); return ( { if (canSubmit && submitRef.current) { - setValue("status", "COMPLETE"); + setValue("status", "PENDING"); submitRef.current.click(); } }, []); diff --git a/src/components/template/template-field-form/index.tsx b/src/components/template/template-field-form/index.tsx index e969c5506..03f3cd0c7 100644 --- a/src/components/template/template-field-form/index.tsx +++ b/src/components/template/template-field-form/index.tsx @@ -31,7 +31,7 @@ export const TemplateFieldForm = ({ toast.error(`${title}, ${message}`); } - if (status === "COMPLETE") { + if (status === "PENDING") { router.push(`/${companyPublicId}/documents/esign`); } }, diff --git a/src/constants/job.ts b/src/constants/job.ts index 83eb00d06..df1c30f19 100644 --- a/src/constants/job.ts +++ b/src/constants/job.ts @@ -8,5 +8,5 @@ export const JOB_TYPES = { "esign-confirmation", "esign-notification", ], - generate: ["esign-pdf"], + esign: ["generate-pdf", "complete-pdf"], } as const; diff --git a/src/emails/EsignConfirmationEmail.tsx b/src/emails/EsignConfirmationEmail.tsx index 0dbb94ff6..f616aa3aa 100644 --- a/src/emails/EsignConfirmationEmail.tsx +++ b/src/emails/EsignConfirmationEmail.tsx @@ -10,9 +10,9 @@ import { Text, } from "@react-email/components"; -import type { ConfirmationEmailPayloadType } from "../jobs/esign-confirmation-email"; +import type { TSchema } from "../jobs/esign-confirmation-email"; -type Payload = Omit; +type Payload = Omit; const ESignConfirmationEmail = ({ documentName, diff --git a/src/emails/EsignEmail.tsx b/src/emails/EsignEmail.tsx index 9f7aecd4e..ba74d18b1 100644 --- a/src/emails/EsignEmail.tsx +++ b/src/emails/EsignEmail.tsx @@ -1,4 +1,4 @@ -import type { EsignEmailPayloadType } from "@/jobs/esign-email"; +import type { TESignNotificationEmailJobInput } from "@/jobs/esign-email"; import { Body, Button, @@ -21,7 +21,12 @@ import { UserAvatarIcon, } from "../components/common/icons"; -type TEsignEmailProps = EsignEmailPayloadType & { signingLink: string }; +type TEsignEmailProps = Omit< + TESignNotificationEmailJobInput, + "token" | "email" | "userAgent" | "requestIp" | "companyId" +> & { + signingLink: string; +}; const EsignEmail = ({ signingLink, diff --git a/src/env.js b/src/env.js index 3732389e2..6a914b993 100644 --- a/src/env.js +++ b/src/env.js @@ -60,6 +60,9 @@ export const env = createEnv({ // sentry SENTRY_ORG: z.string().optional(), SENTRY_PROJECT: z.string().optional(), + + //job queue + QUEUE_DATABASE_URL: z.string().optional(), }, /** @@ -116,6 +119,9 @@ export const env = createEnv({ NEXT_PUBLIC_SENTRY_DSN: readRuntimePublicEnvVariable( "NEXT_PUBLIC_SENTRY_DSN", ), + + /// job queue + WORKER_DATABASE_URL: process.env.WORKER_DATABASE_URL, }, /** * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially diff --git a/src/instrumentation.ts b/src/instrumentation.ts index 77903006a..baac0625b 100644 --- a/src/instrumentation.ts +++ b/src/instrumentation.ts @@ -2,8 +2,9 @@ import { isSentryEnabled } from "@/constants/sentry"; export async function register() { if (process.env.NEXT_RUNTIME === "nodejs") { - const { startJobs } = await import("@/jobs/start"); - await startJobs(); + const { registerJobs } = await import("@/jobs/register"); + + await registerJobs(); if (isSentryEnabled) { await import("../sentry.server.config"); diff --git a/src/jobs/auth-verification-email.ts b/src/jobs/auth-verification-email.ts index a90009e03..ec52111d0 100644 --- a/src/jobs/auth-verification-email.ts +++ b/src/jobs/auth-verification-email.ts @@ -1,23 +1,25 @@ import AccountVerificationEmail from "@/emails/AccountVerificationEmail"; import { env } from "@/env"; -import { BaseJob } from "@/jobs/base"; import { sendMail } from "@/server/mailer"; -import { renderAsync } from "@react-email/components"; -import type { Job } from "pg-boss"; +import { render } from "@react-email/components"; +import { z } from "zod"; +import { defineJob, defineWorker, defineWorkerConfig } from "../lib/queue"; -export type AuthVerificationPayloadType = { - email: string; - token: string; -}; +const config = defineWorkerConfig({ + name: "email.auth-verify", + schema: z.object({ + email: z.string(), + token: z.string(), + }), +}); -export const sendAuthVerificationEmail = async ( - payload: AuthVerificationPayloadType, -) => { - const { email, token } = payload; +export const authVerificationEmailJob = defineJob(config); +export const authVerificationEmailWorker = defineWorker(config, async (job) => { + const { email, token } = job.data; const baseUrl = env.NEXT_PUBLIC_BASE_URL; const confirmLink = `${baseUrl}/verify-email/${token}`; - const html = await renderAsync( + const html = await render( AccountVerificationEmail({ verifyLink: confirmLink, }), @@ -28,12 +30,4 @@ export const sendAuthVerificationEmail = async ( subject: "Confirm your email", html, }); -}; - -export class AuthVerificationEmailJob extends BaseJob { - readonly type = "email.auth-verify"; - - async work(job: Job): Promise { - await sendAuthVerificationEmail(job.data); - } -} +}); diff --git a/src/jobs/base.ts b/src/jobs/base.ts deleted file mode 100644 index e506ea253..000000000 --- a/src/jobs/base.ts +++ /dev/null @@ -1,106 +0,0 @@ -import type { JOB_TYPES } from "@/constants/job"; -import { env } from "@/env"; -import { logger } from "@/lib/logger"; -import { singleton } from "@/lib/singleton"; -import pgBoss from "pg-boss"; - -type JobTypes = typeof JOB_TYPES; - -const log = logger.child({ module: "jobs" }); - -export type JobType = { - [Key in keyof JobTypes]: `${Key}.${JobTypes[Key][number]}`; -}[keyof JobTypes]; - -interface Job { - type: JobType; - options: pgBoss.SendOptions; - start: () => Promise; - work: (job: pgBoss.Job) => Promise; - emit: (data: T) => Promise; -} - -export abstract class BaseJob implements Job { - protected boss: pgBoss; - abstract readonly type: JobType; - readonly options = { retryLimit: 3, retryDelay: 1000 }; - - constructor() { - this.boss = boss; - } - - async start(): Promise { - await this.boss.work(this.type, this.work.bind(this)); - } - - abstract work(job: pgBoss.Job): Promise; - - async emit(data: T, options?: pgBoss.SendOptions): Promise { - await this.boss.send(this.type, data, options ?? this.options); - } - async bulkEmit(data: Omit, "name">[]): Promise { - await this.boss.insert( - data.map((items) => ({ ...items, name: this.type })), - ); - } -} - -export class JobManager { - private readonly boss: pgBoss; - // biome-ignore lint/suspicious/noExplicitAny: - private jobs = new Map>(); - - constructor(boss: pgBoss) { - this.boss = boss; - } - - // biome-ignore lint/suspicious/noExplicitAny: - register(job: new (boss: pgBoss) => Job): JobManager { - const jobInstance = new job(this.boss); - this.jobs.set(jobInstance.type, jobInstance); - return this; - } - - async start(): Promise { - const startTime = Date.now(); - log.info("Starting pg-boss job queue manager"); - - await this.boss.start(); - - const endTime = Date.now(); - const elapsedTime = endTime - startTime; - - log.info( - `Successfully started pg-boss job queue manager in ${elapsedTime}ms`, - ); - - for (const [jobName, job] of this.jobs.entries()) { - const jobStartTime = Date.now(); - log.info(`Registering pg-boss job:${jobName}`); - - await job.start(); - - const jobEndTime = Date.now(); - const jobElapsedTime = jobEndTime - jobStartTime; - - log.info( - `Successfully registered pg-boss job:${jobName} in ${jobElapsedTime}ms`, - ); - } - } -} - -export const boss = singleton( - "pg-boss", - () => - new pgBoss({ - connectionString: env.DATABASE_URL, - max: 5, - retryBackoff: true, - retryLimit: 4, - expireInHours: 48, - archiveCompletedAfterSeconds: 60 * 60 * 2, // 2 hours - deleteAfterDays: 2, - retentionDays: 2, - }), -); diff --git a/src/jobs/esign-complete-pdf.ts b/src/jobs/esign-complete-pdf.ts new file mode 100644 index 000000000..cfd96c835 --- /dev/null +++ b/src/jobs/esign-complete-pdf.ts @@ -0,0 +1,83 @@ +import { db } from "@/server/db"; +import { completeEsignDocuments } from "@/server/esign"; +import { getPresignedGetUrl } from "@/server/file-uploads"; +import { z } from "zod"; +import { defineJob, defineWorker, defineWorkerConfig } from "../lib/queue"; +import { eSignConfirmationEmailJob } from "./esign-confirmation-email"; + +export const Schema = z.object({ + company: z.object({ + name: z.string(), + logo: z.string().nullish(), + }), + + templateId: z.string(), + requestIp: z.string(), + userAgent: z.string(), + + templateName: z.string(), + companyId: z.string(), + recipients: z.array( + z.object({ + email: z.string(), + name: z.string().nullish(), + }), + ), + sender: z.object({ + email: z.string().email(), + name: z.string(), + }), + bucketData: z.object({ + key: z.string(), + name: z.string(), + mimeType: z.string(), + size: z.number(), + }), +}); + +const config = defineWorkerConfig({ + name: "esign.complete-pdf", + schema: Schema, +}); + +export const eSignCompletePDFJob = defineJob(config); +export const eSignCompletePDFWorker = defineWorker(config, async (job) => { + const { + companyId, + templateName, + requestIp, + userAgent, + sender, + templateId, + recipients, + company, + bucketData, + } = job.data; + + await db.$transaction(async (tx) => { + await completeEsignDocuments({ + bucketData: bucketData, + companyId, + db: tx, + requestIp, + templateId, + uploaderName: sender.name, + userAgent, + }); + }); + + const file = await getPresignedGetUrl(bucketData.key); + + await eSignConfirmationEmailJob.bulkEmit( + recipients.map((recipient) => ({ + data: { + fileUrl: file.url, + documentName: templateName, + recipient, + company, + senderName: sender.name, + senderEmail: sender.email, + }, + })), + ); +}); diff --git a/src/jobs/esign-confirmation-email.ts b/src/jobs/esign-confirmation-email.ts index 850f9bb9f..c37cce30b 100644 --- a/src/jobs/esign-confirmation-email.ts +++ b/src/jobs/esign-confirmation-email.ts @@ -1,55 +1,61 @@ import ESignConfirmationEmail from "@/emails/EsignConfirmationEmail"; -import { BaseJob } from "@/jobs/base"; import { sendMail } from "@/server/mailer"; -import { renderAsync } from "@react-email/components"; -import type { Job } from "pg-boss"; +import { render } from "@react-email/components"; +import { z } from "zod"; +import { defineJob, defineWorker, defineWorkerConfig } from "../lib/queue"; -export type ConfirmationEmailPayloadType = { - fileUrl: string; - documentName: string; - senderName: string | null; - senderEmail: string | null; - company: { - name: string; - logo?: string | null; - }; - recipient: { name?: string | null; email: string }; -}; +const Schema = z.object({ + fileUrl: z.string(), + documentName: z.string(), + senderName: z.string().nullable(), + senderEmail: z.string().nullable(), + company: z.object({ + name: z.string(), + logo: z.string().nullish(), + }), + recipient: z.object({ + name: z.string().nullish(), + email: z.string().email(), + }), +}); -export const sendEsignConfirmationEmail = async ( - payload: ConfirmationEmailPayloadType, -) => { - const html = await renderAsync( - ESignConfirmationEmail({ - documentName: payload.documentName, - recipient: payload.recipient, - senderName: payload.senderName, - senderEmail: payload.senderEmail, - company: payload.company, - }), - ); - await sendMail({ - to: payload.recipient.email, - ...(payload.senderEmail && { replyTo: payload.senderEmail }), - subject: "Completed e-signed documents from all parties", - html, - attachments: [ - { - filename: payload.documentName, - path: payload.fileUrl, - }, - ], +const config = defineWorkerConfig({ + name: "email.esign-confirmation", + schema: Schema, +}); + +export type TSchema = z.infer; - headers: { - "X-From-Name": payload.senderName || "Captable", - }, - }); -}; +export const eSignConfirmationEmailJob = defineJob(config); +export const eSignConfirmationEmailWorker = defineWorker( + config, + async (job) => { + const payload = job.data; -export class EsignConfirmationEmailJob extends BaseJob { - readonly type = "email.esign-confirmation"; + const html = await render( + ESignConfirmationEmail({ + documentName: payload.documentName, + recipient: payload.recipient, + senderName: payload.senderName, + senderEmail: payload.senderEmail, + company: payload.company, + }), + ); + await sendMail({ + to: payload.recipient.email, + ...(payload.senderEmail && { replyTo: payload.senderEmail }), + subject: "Completed e-signed documents from all parties", + html, + attachments: [ + { + filename: payload.documentName, + path: payload.fileUrl, + }, + ], - async work(job: Job): Promise { - await sendEsignConfirmationEmail(job.data); - } -} + headers: { + "X-From-Name": payload.senderName || "Captable", + }, + }); + }, +); diff --git a/src/jobs/esign-email.ts b/src/jobs/esign-email.ts index 6fc1e8766..315e12f54 100644 --- a/src/jobs/esign-email.ts +++ b/src/jobs/esign-email.ts @@ -1,62 +1,64 @@ +import { dayjsExt } from "@/common/dayjs"; import EsignEmail from "@/emails/EsignEmail"; import { env } from "@/env"; -import { BaseJob } from "@/jobs/base"; +import { EsignAudit } from "@/server/audit"; import { db } from "@/server/db"; import { sendMail } from "@/server/mailer"; -import { renderAsync } from "@react-email/components"; -import type { Job } from "pg-boss"; +import { render } from "@react-email/components"; +import { z } from "zod"; +import { defineJob, defineWorker, defineWorkerConfig } from "../lib/queue"; -export interface EsignEmailPayloadType { - documentName?: string; - message?: string | null; - recipient: { - id: string; - name: string | null | undefined; - email: string; - }; - sender?: { - name: string | null | undefined; - email: string | null | undefined; - }; - company?: { - name: string; - logo: string | null | undefined; - }; -} +const Schema = z.object({ + documentName: z.string().optional(), + message: z.string().nullish(), + recipient: z.object({ + id: z.string(), + name: z.string().nullish(), + email: z.string().email(), + }), + sender: z + .object({ + name: z.string().nullish(), + email: z.string().email().nullish(), + }) + .optional(), + company: z + .object({ + name: z.string(), + logo: z.string().nullish(), + }) + .optional(), + email: z.string().email(), + token: z.string(), + userAgent: z.string(), + requestIp: z.string(), + companyId: z.string(), +}); -interface AdditionalPayloadType { - email: string; - token: string; -} +export type TESignNotificationEmailJobInput = z.infer; -export type ExtendedEsignPayloadType = EsignEmailPayloadType & - AdditionalPayloadType; +const config = defineWorkerConfig({ + name: "email.esign-notification", + schema: Schema, +}); -export const sendEsignEmail = async (payload: ExtendedEsignPayloadType) => { - const { email, token, sender, ...rest } = payload; - const baseUrl = env.NEXT_PUBLIC_BASE_URL; - const html = await renderAsync( - EsignEmail({ - signingLink: `${baseUrl}/esign/${token}`, +export const eSignNotificationEmailJob = defineJob(config); +export const eSignNotificationEmailWorker = defineWorker( + config, + async (job) => { + const { + email, + token, sender, - ...rest, - }), - ); - await sendMail({ - to: email, - ...(sender?.email && { replyTo: sender.email }), - subject: "eSign Document Request", - html, - headers: { - "X-From-Name": sender?.name || "Captable", - }, - }); -}; + userAgent, + requestIp, + documentName, + companyId, + ...rest + } = job.data; -export class EsignNotificationEmailJob extends BaseJob { - readonly type = "email.esign-notification"; + const baseUrl = env.NEXT_PUBLIC_BASE_URL; - async work(job: Job): Promise { await db.$transaction(async (tx) => { const recipient = await tx.esignRecipient.update({ where: { @@ -67,16 +69,41 @@ export class EsignNotificationEmailJob extends BaseJob }, }); - await tx.template.update({ - where: { - id: recipient.templateId, - }, - data: { - status: "SENT", + await EsignAudit.create( + { + action: "document.email.sent", + companyId, + recipientId: recipient.id, + templateId: recipient.templateId, + ip: requestIp, + location: "", + userAgent, + summary: `${ + sender?.name ? sender.name : "" + } sent "${documentName}" to ${ + recipient.name ? recipient.name : "" + } for eSignature at ${dayjsExt(new Date()).format("lll")}`, }, - }); + tx, + ); }); - await sendEsignEmail(job.data); - } -} + const html = await render( + EsignEmail({ + signingLink: `${baseUrl}/esign/${token}`, + sender, + documentName, + ...rest, + }), + ); + await sendMail({ + to: email, + ...(sender?.email && { replyTo: sender.email }), + subject: "eSign Document Request", + html, + headers: { + "X-From-Name": sender?.name || "Captable", + }, + }); + }, +); diff --git a/src/jobs/esign-pdf.ts b/src/jobs/esign-pdf.ts index 30edc6a30..1db9a2ca8 100644 --- a/src/jobs/esign-pdf.ts +++ b/src/jobs/esign-pdf.ts @@ -1,100 +1,92 @@ -import { BaseJob } from "@/jobs/base"; -import { db } from "@/server/db"; import { type EsignGetTemplateType, - completeEsignDocuments, generateEsignPdf, + getEsignAudits, uploadEsignDocuments, } from "@/server/esign"; -import { getPresignedGetUrl } from "@/server/file-uploads"; -import type { Job } from "pg-boss"; + +import { dayjsExt } from "@/common/dayjs"; +import { EsignAudit } from "@/server/audit"; +import { db } from "@/server/db"; +import { z } from "zod"; +import { defineJob, defineWorker, defineWorkerConfig } from "../lib/queue"; import { - type ConfirmationEmailPayloadType, - EsignConfirmationEmailJob, -} from "./esign-confirmation-email"; + Schema as EsignCompleteSchema, + eSignCompletePDFJob, +} from "./esign-complete-pdf"; -export type EsignPdfPayloadType = { - fields: EsignGetTemplateType["fields"]; - company: { - name: string; - logo?: string | null | undefined; - }; - data: Record; - templateId: string; - requestIp: string; - userAgent: string; - audits: { - id: string; - summary: string; - action: string; - occurredAt: Date; - }[]; - bucketKey: string; - templateName: string; - companyId: string; - recipients: { email: string; name?: string | null }[]; - sender: { email: string; name?: string | null }; -}; +const fields = z.array(z.any()) as z.ZodType; -export class EsignPdfJob extends BaseJob { - readonly type = "generate.esign-pdf"; +const schema = z + .object({ + fields, + data: z.record(z.string()), + bucketKey: z.string(), + }) + .merge(EsignCompleteSchema.omit({ bucketData: true })); - async work(job: Job): Promise { - const { - bucketKey, - data, - audits, - fields, - companyId, - templateName, - requestIp, - userAgent, - sender, - templateId, - recipients, - company, - } = job.data; +export type TEsignPdfSchema = z.infer; - const modifiedPdfBytes = await generateEsignPdf({ - bucketKey, - data, - fields, - audits, - templateName, - }); - const { fileUrl: _fileUrl, ...bucketData } = await uploadEsignDocuments({ - buffer: Buffer.from(modifiedPdfBytes), - companyId, - templateName, - }); +const config = defineWorkerConfig({ + name: "esign.generate-pdf", + schema, +}); + +export const eSignPdfJob = defineJob(config); +export const eSignPdfWorker = defineWorker(config, async (job) => { + const { + bucketKey, + data, + fields, + companyId, + templateName, + requestIp, + userAgent, + sender, + templateId, + recipients, + company, + } = job.data; - await db.$transaction(async (tx) => { - await completeEsignDocuments({ - bucketData: bucketData, - companyId, - db: tx, - requestIp, - templateId, - templateName, - uploaderName: sender.name || "Captable", - userAgent, - }); - }); + await EsignAudit.create( + { + action: "document.complete", + companyId, + templateId, + ip: requestIp, + location: "", + userAgent: userAgent, + summary: `"${templateName}" completely signed at ${dayjsExt( + new Date(), + ).format("lll")}`, + }, + db, + ); - const file = await getPresignedGetUrl(bucketData.key); + const audits = await getEsignAudits({ templateId, tx: db }); - const recipientData: { data: ConfirmationEmailPayloadType }[] = - recipients.map((recipient) => ({ - data: { - fileUrl: file.url, - documentName: templateName, - recipient, - company, - senderName: sender.name || "Captable", - senderEmail: sender.email as string, - }, - })); + const modifiedPdfBytes = await generateEsignPdf({ + bucketKey, + data, + fields, + audits, + templateName, + }); + const { fileUrl: _fileUrl, ...bucketData } = await uploadEsignDocuments({ + buffer: Buffer.from(modifiedPdfBytes), + companyId, + templateName, + }); - await new EsignConfirmationEmailJob().bulkEmit(recipientData); - } -} + await eSignCompletePDFJob.emit({ + requestIp, + userAgent, + sender, + templateId, + recipients, + company, + bucketData, + companyId, + templateName, + }); +}); diff --git a/src/jobs/member-inivite-email.ts b/src/jobs/member-inivite-email.ts index 8801881a8..61fd05bda 100644 --- a/src/jobs/member-inivite-email.ts +++ b/src/jobs/member-inivite-email.ts @@ -1,30 +1,32 @@ import MemberInviteEmail from "@/emails/MemberInviteEmail"; import { env } from "@/env"; -import { BaseJob } from "@/jobs/base"; import { constants } from "@/lib/constants"; import { sendMail } from "@/server/mailer"; -import { renderAsync } from "@react-email/components"; -import type { Job } from "pg-boss"; - -type MemberInvitePayloadType = { - email: string; - passwordResetToken: string; - user: { - email?: string | null | undefined; - name?: string | null | undefined; - }; - verificationToken: string; - company: { - name: string; - id: string; - }; -}; - -export const sendMemberInviteEmail = async ( - payload: MemberInvitePayloadType, -) => { +import { render } from "@react-email/components"; +import { z } from "zod"; +import { defineJob, defineWorker, defineWorkerConfig } from "../lib/queue"; + +const config = defineWorkerConfig({ + name: "email.member-invite", + schema: z.object({ + email: z.string(), + passwordResetToken: z.string(), + user: z.object({ + email: z.string().email().nullish(), + name: z.string().nullish(), + }), + verificationToken: z.string(), + company: z.object({ + name: z.string(), + id: z.string(), + }), + }), +}); + +export const sendMemberInviteEmailJob = defineJob(config); +export const sendMemberInviteEmailWorker = defineWorker(config, async (job) => { const { email, passwordResetToken, verificationToken, company, user } = - payload; + job.data; const baseUrl = env.NEXT_PUBLIC_BASE_URL; @@ -39,7 +41,7 @@ export const sendMemberInviteEmail = async ( await sendMail({ to: email, subject: `Join ${company.name} on ${constants.title}`, - html: await renderAsync( + html: await render( MemberInviteEmail({ inviteLink, companyName: company.name, @@ -47,12 +49,4 @@ export const sendMemberInviteEmail = async ( }), ), }); -}; - -export class SendMemberInviteEmailJob extends BaseJob { - readonly type = "email.member-invite"; - - async work(job: Job): Promise { - await sendMemberInviteEmail(job.data); - } -} +}); diff --git a/src/jobs/password-reset-email.ts b/src/jobs/password-reset-email.ts index deada70b9..12dbf6b99 100644 --- a/src/jobs/password-reset-email.ts +++ b/src/jobs/password-reset-email.ts @@ -1,24 +1,26 @@ import PasswordResetEmail from "@/emails/PasswordResetEmail"; import { env } from "@/env"; -import { BaseJob } from "@/jobs/base"; import { sendMail } from "@/server/mailer"; -import { renderAsync } from "@react-email/components"; -import type { Job } from "pg-boss"; +import { render } from "@react-email/components"; +import { z } from "zod"; +import { defineJob, defineWorker, defineWorkerConfig } from "../lib/queue"; -export type PasswordResetPayloadType = { - email: string; - token: string; -}; +const config = defineWorkerConfig({ + name: "email.password-reset", + schema: z.object({ + email: z.string(), + token: z.string(), + }), +}); -export const sendPasswordResetEmail = async ( - payload: PasswordResetPayloadType, -) => { - const { email, token } = payload; +export const passwordResetEmailJob = defineJob(config); +export const passwordResetEmailWorker = defineWorker(config, async (job) => { + const { email, token } = job.data; const baseUrl = env.NEXT_PUBLIC_BASE_URL; const confirmLink = `${baseUrl}/reset-password/${token}`; - const html = await renderAsync( + const html = await render( PasswordResetEmail({ resetLink: confirmLink, }), @@ -29,12 +31,4 @@ export const sendPasswordResetEmail = async ( subject: "Reset your password", html, }); -}; - -export class PasswordResetEmailJob extends BaseJob { - readonly type = "email.password-reset"; - - async work(job: Job): Promise { - await sendPasswordResetEmail(job.data); - } -} +}); diff --git a/src/jobs/register.ts b/src/jobs/register.ts new file mode 100644 index 000000000..6f9c5c1a3 --- /dev/null +++ b/src/jobs/register.ts @@ -0,0 +1,25 @@ +import { queueManager } from "../lib/queue"; +import { authVerificationEmailWorker } from "./auth-verification-email"; +import { eSignCompletePDFWorker } from "./esign-complete-pdf"; +import { eSignConfirmationEmailWorker } from "./esign-confirmation-email"; +import { eSignNotificationEmailWorker } from "./esign-email"; +import { eSignPdfWorker } from "./esign-pdf"; +import { sendMemberInviteEmailWorker } from "./member-inivite-email"; +import { passwordResetEmailWorker } from "./password-reset-email"; +import { shareDataRoomEmailWorker } from "./share-data-room-email"; +import { shareUpdateEmailWorker } from "./share-update-email"; + +export async function registerJobs() { + queueManager.register(shareDataRoomEmailWorker); + queueManager.register(shareUpdateEmailWorker); + queueManager.register(passwordResetEmailWorker); + queueManager.register(sendMemberInviteEmailWorker); + queueManager.register(eSignNotificationEmailWorker); + queueManager.register(authVerificationEmailWorker); + queueManager.register(eSignConfirmationEmailWorker); + queueManager.register(eSignPdfWorker); + queueManager.register(eSignCompletePDFWorker); + + //start + await queueManager.start(); +} diff --git a/src/jobs/share-data-room-email.ts b/src/jobs/share-data-room-email.ts index 80329bd94..4343bdcfd 100644 --- a/src/jobs/share-data-room-email.ts +++ b/src/jobs/share-data-room-email.ts @@ -1,22 +1,25 @@ import ShareDataRoomEmail from "@/emails/ShareDataRoomEmail"; -import { BaseJob } from "@/jobs/base"; import { sendMail } from "@/server/mailer"; -import { renderAsync } from "@react-email/components"; -import type { Job } from "pg-boss"; +import { render } from "@react-email/components"; +import { z } from "zod"; +import { defineJob, defineWorker, defineWorkerConfig } from "../lib/queue"; -export type DataRoomEmailPayloadType = { - link: string; - dataRoom: string; - email: string; - senderName: string; - companyName: string; - recipientName?: string | null | undefined; - senderEmail?: string | null | undefined; -}; +const config = defineWorkerConfig({ + name: "email.share-data-room", + schema: z.object({ + link: z.string(), + dataRoom: z.string(), + email: z.string().email(), + senderName: z.string(), + companyName: z.string(), + recipientName: z.string().nullish(), + senderEmail: z.string().email().nullish(), + }), +}); -export const sendShareDataRoomEmail = async ( - payload: DataRoomEmailPayloadType, -) => { +export const shareDataRoomEmailJob = defineJob(config); + +export const shareDataRoomEmailWorker = defineWorker(config, async (job) => { const { dataRoom, link, @@ -25,12 +28,12 @@ export const sendShareDataRoomEmail = async ( senderName, email, senderEmail, - } = payload; + } = job.data; await sendMail({ to: email, ...(senderEmail && { replyTo: senderEmail }), subject: `${senderName} shared a data room - ${dataRoom}`, - html: await renderAsync( + html: await render( ShareDataRoomEmail({ senderName: senderName, recipientName, @@ -44,12 +47,4 @@ export const sendShareDataRoomEmail = async ( "X-From-Name": senderName, }, }); -}; - -export class ShareDataRoomEmailJob extends BaseJob { - readonly type = "email.share-data-room"; - - async work(job: Job): Promise { - await sendShareDataRoomEmail(job.data); - } -} +}); diff --git a/src/jobs/share-update-email.ts b/src/jobs/share-update-email.ts index 19b771354..99d36eb3f 100644 --- a/src/jobs/share-update-email.ts +++ b/src/jobs/share-update-email.ts @@ -1,22 +1,27 @@ import ShareUpdateEmail from "@/emails/ShareUpdateEmail"; -import { BaseJob } from "@/jobs/base"; import { sendMail } from "@/server/mailer"; -import { renderAsync } from "@react-email/components"; -import type { Job } from "pg-boss"; +import { render } from "@react-email/components"; +import { z } from "zod"; +import { defineJob, defineWorker, defineWorkerConfig } from "../lib/queue"; -export type UpdateSharePayloadType = { - update: { - title: string; - }; - link: string; - companyName: string; - senderName: string; - email: string; - recipientName?: string | null | undefined; - senderEmail?: string | null | undefined; -}; +const config = defineWorkerConfig({ + name: "email.share-update", + schema: z.object({ + update: z.object({ + title: z.string(), + }), + link: z.string(), + companyName: z.string(), + senderName: z.string(), + email: z.string().email(), + recipientName: z.string().nullish(), + senderEmail: z.string().email().nullish(), + }), +}); -export const sendShareUpdateEmail = async (payload: UpdateSharePayloadType) => { +export const shareUpdateEmailJob = defineJob(config); + +export const shareUpdateEmailWorker = defineWorker(config, async (job) => { const { update, link, @@ -25,12 +30,12 @@ export const sendShareUpdateEmail = async (payload: UpdateSharePayloadType) => { senderName, email, senderEmail, - } = payload; + } = job.data; await sendMail({ to: email, ...(senderEmail && { replyTo: senderEmail }), subject: `${senderName} shared an update - ${update.title}`, - html: await renderAsync( + html: await render( ShareUpdateEmail({ senderName: senderName, recipientName, @@ -44,12 +49,4 @@ export const sendShareUpdateEmail = async (payload: UpdateSharePayloadType) => { "X-From-Name": senderName, }, }); -}; - -export class ShareUpdateEmailJob extends BaseJob { - readonly type = "email.share-update"; - - async work(job: Job): Promise { - await sendShareUpdateEmail(job.data); - } -} +}); diff --git a/src/jobs/start.ts b/src/jobs/start.ts deleted file mode 100644 index 4126116f8..000000000 --- a/src/jobs/start.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { AuthVerificationEmailJob } from "@/jobs/auth-verification-email"; -import { JobManager, boss } from "@/jobs/base"; -import { EsignConfirmationEmailJob } from "@/jobs/esign-confirmation-email"; -import { EsignNotificationEmailJob } from "@/jobs/esign-email"; -import { EsignPdfJob } from "@/jobs/esign-pdf"; -import { SendMemberInviteEmailJob } from "@/jobs/member-inivite-email"; -import { PasswordResetEmailJob } from "@/jobs/password-reset-email"; -import { ShareDataRoomEmailJob } from "@/jobs/share-data-room-email"; -import { ShareUpdateEmailJob } from "@/jobs/share-update-email"; - -export async function startJobs() { - const jobs = new JobManager(boss) - .register(AuthVerificationEmailJob) - .register(ShareUpdateEmailJob) - .register(ShareDataRoomEmailJob) - .register(SendMemberInviteEmailJob) - .register(PasswordResetEmailJob) - .register(EsignNotificationEmailJob) - .register(EsignConfirmationEmailJob) - .register(EsignPdfJob); - - await jobs.start(); -} diff --git a/src/lib/queue.ts b/src/lib/queue.ts new file mode 100644 index 000000000..4da6cb491 --- /dev/null +++ b/src/lib/queue.ts @@ -0,0 +1,121 @@ +import type { JOB_TYPES } from "@/constants/job"; +import { logger } from "@/lib/logger"; +import { singleton } from "@/lib/singleton"; +import PgBoss from "pg-boss"; +import type { z } from "zod"; + +const CONNECTION_URL = + process.env.QUEUE_DATABASE_URL ?? (process.env.DATABASE_URL as string); + +const queue = singleton( + "pg-boss", + () => + new PgBoss({ + connectionString: CONNECTION_URL, + max: 5, + retryBackoff: true, + retryLimit: 4, + archiveCompletedAfterSeconds: 60 * 60 * 2, // 2 hours + deleteAfterDays: 2, + retentionDays: 2, + schema: "captable_queue", + }), +); + +type JobTypes = typeof JOB_TYPES; + +const log = logger.child({ module: "queue" }); +const logPrefix = (msg: string) => `[Queue] ${msg}`; + +export type JobType = { + [Key in keyof JobTypes]: `${Key}.${JobTypes[Key][number]}`; +}[keyof JobTypes]; + +interface WorkerFactory { + name: JobType; + // biome-ignore lint/suspicious/noExplicitAny: + handler: PgBoss.WorkHandler; +} + +function createQueue() { + const jobs = new Map(); + + async function start() { + log.info(logPrefix("Starting queue manager")); + + queue.on("error", (error) => { + log.error(logPrefix("error"), { + type: "queue", + error, + }); + }); + + await queue.start(); + + for (const [jobName, job] of jobs.entries()) { + log.info(logPrefix(`Registering job:${jobName}`)); + + await queue.createQueue(jobName); + await queue.work(jobName, job.handler); + } + } + + function register(jobFactory: WorkerFactory) { + jobs.set(jobFactory.name, jobFactory); + } + + return { start, register }; +} + +const queueManager = createQueue(); + +function defineWorker< + U extends ReturnType, + T extends U["schema"], + V, +>(config: U, handler: (data: PgBoss.Job>) => Promise) { + return { + name: config.name, + handler: ([job]: PgBoss.Job>[]) => { + if (!job) { + throw new Error(""); + } + + return handler(job); + }, + }; +} + +function defineJob>(config: U) { + type TSchema = U["schema"]; + return { + emit: (data: z.infer, options?: PgBoss.JobOptions) => { + const data_ = config.schema.parse(data); + + return queue.send(config.name, data_, options ?? {}); + }, + bulkEmit: (data: Omit>, "name">[]) => { + for (const item of data) { + config.schema.parse(item.data); + } + + return queue.insert( + data.map((items) => ({ ...items, name: config.name })), + ); + }, + }; +} + +interface defineWorkerConfigOptions { + schema: T; + name: JobType; +} + +// biome-ignore lint/suspicious/noExplicitAny: +function defineWorkerConfig>( + opts: defineWorkerConfigOptions, +) { + return opts; +} + +export { queue, queueManager, defineWorkerConfig, defineJob, defineWorker }; diff --git a/src/providers/template-field-provider.tsx b/src/providers/template-field-provider.tsx index b6cbb3fbd..9b63541bf 100644 --- a/src/providers/template-field-provider.tsx +++ b/src/providers/template-field-provider.tsx @@ -3,9 +3,9 @@ import { Form } from "@/components/ui/form"; import { COLORS } from "@/constants/esign"; import { FieldTypes, TemplateStatus } from "@/prisma/enums"; -import { type RouterOutputs } from "@/trpc/shared"; +import type { RouterOutputs } from "@/trpc/shared"; import { zodResolver } from "@hookform/resolvers/zod"; -import { type ReactNode } from "react"; +import type { ReactNode } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; @@ -19,7 +19,7 @@ interface TemplateFieldProviderProps { } const formSchema = z.object({ - status: z.nativeEnum(TemplateStatus), + status: z.enum([TemplateStatus.PENDING, TemplateStatus.DRAFT]), fieldType: z.nativeEnum(FieldTypes).optional(), fields: z .array( diff --git a/src/server/esign.ts b/src/server/esign.ts index d729fe986..a70b81678 100644 --- a/src/server/esign.ts +++ b/src/server/esign.ts @@ -224,7 +224,6 @@ export async function uploadEsignDocuments({ } export interface CompleteEsignDocumentsOptionsType { - templateName: string; companyId: string; db: PrismaTransactionalClient; requestIp: string; @@ -239,7 +238,6 @@ export async function completeEsignDocuments({ db, requestIp, templateId, - templateName, uploaderName, userAgent, bucketData, @@ -250,24 +248,10 @@ export async function completeEsignDocuments({ }, data: { completedOn: new Date(), + status: "COMPLETE", }, }); - await EsignAudit.create( - { - action: "document.complete", - companyId, - templateId, - ip: requestIp, - location: "", - userAgent: userAgent, - summary: `"${templateName}" completely signed at ${dayjsExt( - new Date(), - ).format("lll")}`, - }, - db, - ); - const { id: bucketId, name } = await createBucketHandler({ db, input: { ...bucketData, tags: [TAG.ESIGN] }, diff --git a/src/services/esign-service.ts b/src/services/esign-service.ts new file mode 100644 index 000000000..a34f0070d --- /dev/null +++ b/src/services/esign-service.ts @@ -0,0 +1,192 @@ +import { dayjsExt } from "@/common/dayjs"; +import { + type TESignNotificationEmailJobInput, + eSignNotificationEmailJob, +} from "@/jobs/esign-email"; +import { type TEsignPdfSchema, eSignPdfJob } from "@/jobs/esign-pdf"; +import { EsignAudit } from "@/server/audit"; +import type { TEsignAuditSchema } from "@/server/audit/schema"; +import type { TPrismaOrTransaction } from "@/server/db"; +import { type EsignGetTemplateType, getEsignTemplate } from "@/server/esign"; +import { EncodeEmailToken } from "@/trpc/routers/template-field-router/procedures/add-fields"; +import type { EsignRecipientStatus } from "@prisma/client"; + +export class EsignService { + getTemplate(templateId: string, tx: TPrismaOrTransaction) { + return getEsignTemplate({ + templateId, + tx, + }); + } + + getRecipient( + recipientId: string, + templateId: string, + tx: TPrismaOrTransaction, + ) { + return tx.esignRecipient.findFirstOrThrow({ + where: { + id: recipientId, + templateId, + }, + }); + } + + updateRecipientStatus( + recipientId: string, + status: EsignRecipientStatus, + tx: TPrismaOrTransaction, + ) { + return tx.esignRecipient.update({ + where: { id: recipientId }, + data: { status }, + }); + } + + async handleOrderedDelivery( + template: EsignGetTemplateType, + data: Pick< + TESignNotificationEmailJobInput, + "sender" | "requestIp" | "userAgent" + >, + tx: TPrismaOrTransaction, + ) { + const nextDelivery = await tx.esignRecipient.findFirst({ + where: { + templateId: template.id, + status: "PENDING", + }, + select: { + id: true, + email: true, + name: true, + }, + }); + if (nextDelivery) { + const token = await EncodeEmailToken({ + recipientId: nextDelivery.id, + templateId: template.id, + }); + const email = nextDelivery.email; + + await eSignNotificationEmailJob.emit({ + email, + token, + sender: data.sender, + message: template.message, + documentName: template.name, + recipient: nextDelivery, + company: template.company, + companyId: template.companyId, + requestIp: data.requestIp, + userAgent: data.userAgent, + }); + } + } + + async createSignedAuditLog( + data: Omit & { + recipientName?: string | null; + templateName: string; + browser?: string; + }, + tx: TPrismaOrTransaction, + ) { + const { recipientName, templateName, browser, ...rest } = data; + + await EsignAudit.create( + { + action: "recipient.signed", + ...rest, + summary: `${ + recipientName ?? "unknown recipient" + } signed "${templateName}" on ${ + browser ?? "unknown browser" + } at ${dayjsExt(new Date()).format("lll")}`, + }, + tx, + ); + } + + async completeDocument( + options: Omit & { + sender: { + name: string | null; + email: string | null; + }; + }, + ) { + await eSignPdfJob.emit( + { + ...options, + sender: { + name: options.sender.name ?? "Captable", + email: options.sender.email ?? "Unknown email", + }, + }, + { + singletonKey: `esign-${options.templateId}`, + }, + ); + } + + getAllRecipients(templateId: string, tx: TPrismaOrTransaction) { + return tx.esignRecipient.findMany({ + where: { + templateId, + }, + select: { + email: true, + name: true, + status: true, + }, + }); + } + + async saveFieldValues( + fields: EsignGetTemplateType["fields"], + data: Record, + tx: TPrismaOrTransaction, + ) { + for (const field of fields) { + const value = data?.[field?.id]; + + if (value) { + await tx.templateField.update({ + where: { + id: field.id, + }, + data: { + prefilledValue: value, + }, + }); + } + } + } + + async getFieldValues(templateId: string, tx: TPrismaOrTransaction) { + const values = await tx.templateField.findMany({ + where: { + templateId, + prefilledValue: { + not: null, + }, + }, + select: { + id: true, + prefilledValue: true, + }, + }); + + const data: Record = values.reduce>( + (prev, curr) => { + prev[curr.id] = curr.prefilledValue ?? ""; + + return prev; + }, + {}, + ); + + return data; + } +} diff --git a/src/trpc/routers/auth/procedure/forgot-password.ts b/src/trpc/routers/auth/procedure/forgot-password.ts index 767f4cdfc..d2b79db50 100644 --- a/src/trpc/routers/auth/procedure/forgot-password.ts +++ b/src/trpc/routers/auth/procedure/forgot-password.ts @@ -1,4 +1,4 @@ -import { PasswordResetEmailJob } from "@/jobs/password-reset-email"; +import { passwordResetEmailJob } from "@/jobs/password-reset-email"; import { generatePasswordResetToken } from "@/lib/token"; import { getUserByEmail } from "@/server/user"; import { withoutAuth } from "@/trpc/api/trpc"; @@ -18,7 +18,7 @@ export const forgotPasswordProcedure = withoutAuth } const { email, token } = await generatePasswordResetToken(input); - await new PasswordResetEmailJob().emit({ email, token }); + await passwordResetEmailJob.emit({ email, token }); return { success: true, diff --git a/src/trpc/routers/auth/procedure/resend-email.ts b/src/trpc/routers/auth/procedure/resend-email.ts index 24260cbc1..7617be506 100644 --- a/src/trpc/routers/auth/procedure/resend-email.ts +++ b/src/trpc/routers/auth/procedure/resend-email.ts @@ -1,4 +1,4 @@ -import { sendAuthVerificationEmail } from "@/jobs/auth-verification-email"; +import { authVerificationEmailJob } from "@/jobs/auth-verification-email"; import { generateVerificationToken } from "@/lib/token"; import { getVerificationTokenByEmail } from "@/server/verification-token"; @@ -19,7 +19,7 @@ export const resendEmailProcedure = withoutAuth } const verificationToken = await generateVerificationToken(input); - await sendAuthVerificationEmail({ + await authVerificationEmailJob.emit({ email: verificationToken.identifier, token: verificationToken.token, }); diff --git a/src/trpc/routers/auth/procedure/signup.ts b/src/trpc/routers/auth/procedure/signup.ts index 37ddefe45..d3cbc3b43 100644 --- a/src/trpc/routers/auth/procedure/signup.ts +++ b/src/trpc/routers/auth/procedure/signup.ts @@ -1,4 +1,4 @@ -import { sendAuthVerificationEmail } from "@/jobs/auth-verification-email"; +import { authVerificationEmailJob } from "@/jobs/auth-verification-email"; import { generateVerificationToken } from "@/lib/token"; import { Audit } from "@/server/audit"; @@ -52,7 +52,7 @@ export const signupProcedure = withoutAuth const verificationToken = await generateVerificationToken(email); - await sendAuthVerificationEmail({ + await authVerificationEmailJob.emit({ email: verificationToken.identifier, token: verificationToken.token, }); diff --git a/src/trpc/routers/data-room-router/router.ts b/src/trpc/routers/data-room-router/router.ts index 51b15ddd4..200086780 100644 --- a/src/trpc/routers/data-room-router/router.ts +++ b/src/trpc/routers/data-room-router/router.ts @@ -1,9 +1,6 @@ import { generatePublicId } from "@/common/id"; import { env } from "@/env"; -import { - type DataRoomEmailPayloadType, - ShareDataRoomEmailJob, -} from "@/jobs/share-data-room-email"; +import { shareDataRoomEmailJob } from "@/jobs/share-data-room-email"; import { encode } from "@/lib/jwt"; import { ShareRecipientSchema } from "@/schema/contacts"; import { Audit } from "@/server/audit"; @@ -285,7 +282,7 @@ export const dataRoomRouter = createTRPCRouter({ const link = `${baseUrl}/data-rooms/${dataRoom.publicId}?token=${token}`; - const payload: DataRoomEmailPayloadType = { + await shareDataRoomEmailJob.emit({ senderName: `${senderName}`, recipientName: recipient.name, companyName: company.name, @@ -293,9 +290,7 @@ export const dataRoomRouter = createTRPCRouter({ link, email, senderEmail, - }; - - await new ShareDataRoomEmailJob().emit(payload); + }); await db.$transaction(async (tx) => { await Audit.create( diff --git a/src/trpc/routers/member-router/procedures/invite-member.ts b/src/trpc/routers/member-router/procedures/invite-member.ts index b1983474e..9ab9128c8 100644 --- a/src/trpc/routers/member-router/procedures/invite-member.ts +++ b/src/trpc/routers/member-router/procedures/invite-member.ts @@ -1,4 +1,4 @@ -import { SendMemberInviteEmailJob } from "@/jobs/member-inivite-email"; +import { sendMemberInviteEmailJob } from "@/jobs/member-inivite-email"; import { getRoleById } from "@/lib/rbac/access-control"; import { generatePasswordResetToken } from "@/lib/token"; import { Audit } from "@/server/audit"; @@ -141,7 +141,7 @@ export const inviteMemberProcedure = withAccessControl }, ); - const payload = { + await sendMemberInviteEmailJob.emit({ verificationToken, passwordResetToken, email, @@ -150,9 +150,7 @@ export const inviteMemberProcedure = withAccessControl email: user.email, name: user.name, }, - }; - - await new SendMemberInviteEmailJob().emit(payload); + }); return { success: true }; }); diff --git a/src/trpc/routers/member-router/procedures/re-invite.ts b/src/trpc/routers/member-router/procedures/re-invite.ts index 57b86f9c9..9a6596cca 100644 --- a/src/trpc/routers/member-router/procedures/re-invite.ts +++ b/src/trpc/routers/member-router/procedures/re-invite.ts @@ -1,4 +1,4 @@ -import { SendMemberInviteEmailJob } from "@/jobs/member-inivite-email"; +import { sendMemberInviteEmailJob } from "@/jobs/member-inivite-email"; import { generatePasswordResetToken } from "@/lib/token"; import { Audit } from "@/server/audit"; import { checkMembership } from "@/server/auth"; @@ -93,7 +93,7 @@ export const reInviteProcedure = withAuth return { verificationToken, company, email, passwordResetToken }; }); - const payload = { + await sendMemberInviteEmailJob.emit({ verificationToken, passwordResetToken, email, @@ -102,9 +102,7 @@ export const reInviteProcedure = withAuth email: user.email, name: user.name, }, - }; - - await new SendMemberInviteEmailJob().emit(payload); + }); return { success: true }; }); diff --git a/src/trpc/routers/template-field-router/procedures/add-fields.ts b/src/trpc/routers/template-field-router/procedures/add-fields.ts index 4de007b54..1c27f9a23 100644 --- a/src/trpc/routers/template-field-router/procedures/add-fields.ts +++ b/src/trpc/routers/template-field-router/procedures/add-fields.ts @@ -1,7 +1,6 @@ -/* eslint-disable @typescript-eslint/prefer-for-of */ import { - EsignNotificationEmailJob, - type ExtendedEsignPayloadType, + type TESignNotificationEmailJobInput, + eSignNotificationEmailJob, } from "@/jobs/esign-email"; import { decode, encode } from "@/lib/jwt"; import { Audit } from "@/server/audit"; @@ -46,9 +45,9 @@ export const addFieldProcedure = withAuth try { const user = ctx.session.user; const { userAgent, requestIp } = ctx; - const mails: ExtendedEsignPayloadType[] = []; + const mails: TESignNotificationEmailJobInput[] = []; - if (input.status === "COMPLETE" && (!user.email || !user.name)) { + if (input.status === "PENDING" && (!user.email || !user.name)) { return { success: false, title: "Validation failed", @@ -147,7 +146,7 @@ export const addFieldProcedure = withAuth }, }); - if (input.status === "COMPLETE") { + if (input.status === "PENDING") { const nonDeletableRecipientIdList = recipientList.map( (item) => item.id, ); @@ -190,6 +189,9 @@ export const addFieldProcedure = withAuth name: template.company.name, logo: template.company.logo, }, + requestIp, + companyId, + userAgent, }); if (template.orderedDelivery) { @@ -202,7 +204,7 @@ export const addFieldProcedure = withAuth }); if (mails.length) { - new EsignNotificationEmailJob().bulkEmit( + await eSignNotificationEmailJob.bulkEmit( mails.map((data) => ({ data, singletonKey: `esign-notify-${template.id}-${data.recipient.id}`, @@ -213,9 +215,9 @@ export const addFieldProcedure = withAuth return { success: true, title: - input.status === "COMPLETE" ? "Sent for e-sign" : "Saved in draft", + input.status === "PENDING" ? "Sent for e-sign" : "Saved in draft", message: - input.status === "COMPLETE" + input.status === "PENDING" ? "Successfully sent document for e-signature." : "Your template fields has been created.", }; diff --git a/src/trpc/routers/template-field-router/schema.ts b/src/trpc/routers/template-field-router/schema.ts index db84a96dc..0f7f273e5 100644 --- a/src/trpc/routers/template-field-router/schema.ts +++ b/src/trpc/routers/template-field-router/schema.ts @@ -12,7 +12,7 @@ const TemplateFieldMetaType = z.object({ export type TTemplateFieldMetaType = z.infer; export const ZodAddFieldMutationSchema = z.object({ - status: z.nativeEnum(TemplateStatus), + status: z.enum([TemplateStatus.DRAFT, TemplateStatus.PENDING]), templatePublicId: z.string(), data: z.array( z.object({ diff --git a/src/trpc/routers/template-router/procedures/get-signing-fields.tsx b/src/trpc/routers/template-router/procedures/get-signing-fields.tsx index f1cae2120..caf800f27 100644 --- a/src/trpc/routers/template-router/procedures/get-signing-fields.tsx +++ b/src/trpc/routers/template-router/procedures/get-signing-fields.tsx @@ -25,6 +25,9 @@ export const getSigningFieldsProcedure = withoutAuth const { bucket, status } = await tx.template.findFirstOrThrow({ where: { id: recipient.templateId, + status: { + notIn: ["COMPLETE", "DRAFT"], + }, }, select: { bucket: { diff --git a/src/trpc/routers/template-router/procedures/sign-template.ts b/src/trpc/routers/template-router/procedures/sign-template.ts index 2f966124c..454f0f2b3 100644 --- a/src/trpc/routers/template-router/procedures/sign-template.ts +++ b/src/trpc/routers/template-router/procedures/sign-template.ts @@ -1,19 +1,6 @@ -/* eslint-disable @typescript-eslint/prefer-for-of */ - -import { dayjsExt } from "@/common/dayjs"; -import { EsignNotificationEmailJob } from "@/jobs/esign-email"; -import { EsignPdfJob } from "@/jobs/esign-pdf"; -import type { TemplateStatus } from "@/prisma/enums"; -import { EsignAudit } from "@/server/audit"; -import { - type CompleteEsignDocumentsOptionsType, - type GenerateEsignSignPdfOptionsType, - getEsignAudits, - getEsignTemplate, - type uploadEsignDocumentsOptions, -} from "@/server/esign"; +import { EsignService } from "@/services/esign-service"; import { withoutAuth } from "@/trpc/api/trpc"; -import { EncodeEmailToken } from "../../template-field-router/procedures/add-fields"; +import { UAParser } from "ua-parser-js"; import { SignTemplateMutationSchema } from "../schema"; export const signTemplateProcedure = withoutAuth @@ -21,165 +8,55 @@ export const signTemplateProcedure = withoutAuth .mutation(async ({ ctx, input }) => { const { db, requestIp, userAgent } = ctx; + const userAgentParser = new UAParser(userAgent); + const userAgentResult = userAgentParser.getResult(); + const browser = userAgentResult.browser.name; + + const eSignService = new EsignService(); + await db.$transaction(async (tx) => { - const template = await getEsignTemplate({ - templateId: input.templateId, - tx, - }); + const template = await eSignService.getTemplate(input.templateId, tx); + const bucketKey = template.bucket.key; const companyId = template.companyId; const templateName = template.name; const sender = template.uploader.user; - - let templateStatus: TemplateStatus = "WAITING"; - - const totalGroups = new Set( + const allRecipients = new Set( template.fields.map((item) => item.recipientId), ); + const isMultiRecipient = allRecipients.size > 1; + const isOrderedDelivery = template.orderedDelivery; - const recipient = await tx.esignRecipient.findFirstOrThrow({ - where: { - id: input.recipientId, - templateId: template.id, - }, - }); - - await tx.esignRecipient.update({ - where: { id: recipient.id }, - data: { status: "SIGNED" }, - }); - - if (totalGroups.size > 1) { - for (const field of template.fields) { - const value = input?.data?.[field?.id]; - - if (value) { - await tx.templateField.update({ - where: { - id: field.id, - }, - data: { - prefilledValue: value, - }, - }); - } - } - - await EsignAudit.create( - { - action: "recipient.signed", - companyId: template.companyId, - recipientId: recipient.id, - templateId: template.id, - ip: ctx.requestIp, - location: "", - userAgent: ctx.userAgent, - summary: `${recipient.name ? recipient.name : ""} signed "${ - template.name - }" on ${ctx.userAgent} at ${dayjsExt(new Date()).format("lll")}`, - }, - tx, - ); - - const allRecipients = await tx.esignRecipient.findMany({ - where: { - templateId: template.id, - }, - select: { - email: true, - name: true, - status: true, - }, - }); - - const signableRecipients = allRecipients.filter( - (item) => item.status !== "SIGNED", - ).length; - - if (signableRecipients === 0) { - const values = await tx.templateField.findMany({ - where: { - templateId: template.id, - prefilledValue: { - not: null, - }, - }, - select: { - id: true, - prefilledValue: true, - }, - }); - - const data: Record = values.reduce< - Record - >((prev, curr) => { - prev[curr.id] = curr.prefilledValue ?? ""; - - return prev; - }, {}); + const recipient = await eSignService.getRecipient( + input.recipientId, + template.id, + tx, + ); - await EsignAudit.create( - { - action: "recipient.signed", - companyId: template.companyId, - recipientId: recipient.id, - templateId: template.id, - ip: ctx.requestIp, - location: "", - userAgent: ctx.userAgent, - summary: `${recipient.name ? recipient.name : ""} signed "${ - template.name - }" on ${ctx.userAgent} at ${dayjsExt(new Date()).format("lll")}`, - }, - tx, - ); + await eSignService.updateRecipientStatus(recipient.id, "SIGNED", tx); - await signPdf({ - bucketKey, - companyId, - templateName, - fields: template.fields, - data, - templateId: template.id, - db: tx, - requestIp, - userAgent, - company: template.company, - recipients: allRecipients.map((item) => ({ - email: item.email, - name: item.name, - })), - sender, - uploaderName: sender.name || "Captable", - }); - - templateStatus = "COMPLETE"; - } - } else { - await EsignAudit.create( - { - action: "recipient.signed", - companyId: template.companyId, - recipientId: recipient.id, - templateId: template.id, - ip: ctx.requestIp, - location: "", - userAgent: ctx.userAgent, - summary: `${recipient.name ? recipient.name : ""} signed "${ - template.name - }" on ${ctx.userAgent} at ${dayjsExt(new Date()).format("lll")}`, - }, - tx, - ); + await eSignService.createSignedAuditLog( + { + browser, + companyId, + recipientId: recipient.id, + templateId: template.id, + ip: ctx.requestIp, + location: "", + userAgent: ctx.userAgent, + templateName: template.name, + recipientName: recipient.name, + }, + tx, + ); - await signPdf({ - bucketKey, + if (!isMultiRecipient) { + await eSignService.completeDocument({ companyId, templateName, fields: template.fields, data: input.data, templateId: template.id, - db: tx, requestIp, userAgent, sender, @@ -190,118 +67,54 @@ export const signTemplateProcedure = withoutAuth }, ], company: template.company, - uploaderName: sender.name || "Captable", + bucketKey, }); - - templateStatus = "COMPLETE"; } - await tx.template.update({ - where: { - id: template.id, - }, - data: { - status: templateStatus, - }, - }); + if (isMultiRecipient) { + await eSignService.saveFieldValues(template.fields, input.data, tx); - if (template.orderedDelivery) { - const nextDelivery = await tx.esignRecipient.findFirst({ - where: { - templateId: template.id, - status: "PENDING", - }, - select: { - id: true, - email: true, - name: true, - }, - }); - if (nextDelivery) { - const token = await EncodeEmailToken({ - recipientId: nextDelivery.id, - templateId: template.id, - }); - const email = nextDelivery.email; + const allRecipients = await eSignService.getAllRecipients( + template.id, + tx, + ); + const areAllRecipientsSigned = allRecipients.every( + (recipient) => recipient.status === "SIGNED", + ); - await EsignAudit.create( - { - action: "document.email.sent", - companyId: template.companyId, - recipientId: recipient.id, - templateId: template.id, - ip: ctx.requestIp, - location: "", - userAgent: ctx.userAgent, - summary: `${sender.name ? sender.name : ""} sent "${ - template.name - }" to ${ - recipient.name ? recipient.name : "" - } for eSignature at ${dayjsExt(new Date()).format("lll")}`, - }, + if (areAllRecipientsSigned) { + const fieldValues = await eSignService.getFieldValues( + template.id, tx, ); - await new EsignNotificationEmailJob().emit({ - email, - token, - sender, - message: template.message, - documentName: template.name, - recipient: nextDelivery, + await eSignService.completeDocument({ + bucketKey, + companyId, + templateName, + fields: template.fields, + data: fieldValues, + templateId: template.id, + requestIp, + userAgent, company: template.company, + recipients: allRecipients.map((item) => ({ + email: item.email, + name: item.name, + })), + sender, }); } } + + if (isOrderedDelivery) { + await eSignService.handleOrderedDelivery( + template, + { sender, requestIp, userAgent }, + tx, + ); + } }); return {}; }); - -interface TSignPdfOptions - extends Omit, - Omit, - Omit { - templateId: string; - company: { - name: string; - logo?: string | null; - }; - sender: { name: string | null; email: string | null }; - recipients: { name: string | null; email: string }[]; -} - -async function signPdf({ - userAgent, - requestIp, - db, - bucketKey, - companyId, - templateName, - data, - fields, - sender, - templateId, - recipients, - company, -}: TSignPdfOptions) { - const audits = await getEsignAudits({ templateId, tx: db }); - - await new EsignPdfJob().emit( - { - bucketKey, - data, - fields, - audits, - companyId, - requestIp, - templateId, - templateName, - userAgent, - recipients, - sender: sender as { email: string; name: string }, - company, - }, - { singletonKey: `esign-${templateId}`, useSingletonQueue: true }, - ); -} diff --git a/src/trpc/routers/update/procedures/share-update.ts b/src/trpc/routers/update/procedures/share-update.ts index ad9349ed3..753afe66c 100644 --- a/src/trpc/routers/update/procedures/share-update.ts +++ b/src/trpc/routers/update/procedures/share-update.ts @@ -1,8 +1,5 @@ import { env } from "@/env"; -import { - ShareUpdateEmailJob, - type UpdateSharePayloadType, -} from "@/jobs/share-update-email"; +import { shareUpdateEmailJob } from "@/jobs/share-update-email"; import { encode } from "@/lib/jwt"; import { UpdateStatusEnum } from "@/prisma/enums"; import { ShareRecipientSchema } from "@/schema/contacts"; @@ -88,7 +85,7 @@ export const shareUpdateProcedure = withAuth const link = `${baseUrl}/updates/${update.publicId}?token=${token}`; - const payload: UpdateSharePayloadType = { + await shareUpdateEmailJob.emit({ senderName: `${senderName}`, recipientName: recipient.name, companyName: company.name, @@ -98,9 +95,7 @@ export const shareUpdateProcedure = withAuth link, email, senderEmail, - }; - - await new ShareUpdateEmailJob().emit(payload); + }); } };