From 305c2cf140b2a938637b2e8623e31d624154958c Mon Sep 17 00:00:00 2001 From: Ardeman Date: Thu, 20 Mar 2025 12:31:51 +0800 Subject: [PATCH] feat: integrate getClientIPAddress utility for improved IP address retrieval --- app/routes/_news.detail.$slug.tsx | 6 +- app/routes/actions.log.ads.$id.ts | 6 +- package.json | 8 ++ pnpm-lock.yaml | 222 ++++++++++++++++++++++++++++++ 4 files changed, 234 insertions(+), 8 deletions(-) diff --git a/app/routes/_news.detail.$slug.tsx b/app/routes/_news.detail.$slug.tsx index 16f314f..e066389 100644 --- a/app/routes/_news.detail.$slug.tsx +++ b/app/routes/_news.detail.$slug.tsx @@ -1,4 +1,5 @@ import { isRouteErrorResponse } from 'react-router' +import { getClientIPAddress } from 'remix-utils/get-client-ip-address' import { stripHtml } from 'string-strip-html' import { getCategories } from '~/apis/common/get-categories' @@ -13,10 +14,7 @@ import type { Route } from './+types/_news.detail.$slug' export const loader = async ({ request, params }: Route.LoaderArgs) => { const userAgent = request.headers.get('user-agent') - const ipAddress = - request.headers.get('cf-connecting-ip') || - request.headers.get('x-forwarded-for') || - 'localhost' + const ipAddress = getClientIPAddress(request) || 'localhost' const { userToken: accessToken } = await handleCookie(request) let userData if (accessToken) { diff --git a/app/routes/actions.log.ads.$id.ts b/app/routes/actions.log.ads.$id.ts index 7e5ea84..0552782 100644 --- a/app/routes/actions.log.ads.$id.ts +++ b/app/routes/actions.log.ads.$id.ts @@ -1,4 +1,5 @@ import { data } from 'react-router' +import { getClientIPAddress } from 'remix-utils/get-client-ip-address' import { XiorError } from 'xior' import { createLogAdsRequest } from '~/apis/news/create-log-ads' @@ -8,10 +9,7 @@ import type { Route } from './+types/actions.log.ads.$id' export const action = async ({ request, params }: Route.ActionArgs) => { const userAgent = request.headers.get('user-agent') - const ipAddress = - request.headers.get('cf-connecting-ip') || - request.headers.get('x-forwarded-for') || - 'localhost' + const ipAddress = getClientIPAddress(request) || 'localhost' const { userToken: accessToken } = await handleCookie(request) const { id } = params try { diff --git a/package.json b/package.json index ee9aab2..63efb0c 100644 --- a/package.json +++ b/package.json @@ -14,10 +14,15 @@ "validate": "pnpm lint && pnpm typecheck && pnpm knip" }, "dependencies": { + "@edgefirst-dev/batcher": "^1.0.1", + "@edgefirst-dev/jwt": "^1.2.0", + "@edgefirst-dev/server-timing": "^0.0.1", "@headlessui/react": "^2.2.0", "@heroicons/react": "^2.2.0", "@hookform/resolvers": "^4.1.1", "@monaco-editor/react": "^4.7.0", + "@oslojs/crypto": "^1.0.1", + "@oslojs/encoding": "^1.1.0", "@react-router/fs-routes": "^7.1.3", "@react-router/node": "^7.1.3", "@react-router/serve": "^7.1.3", @@ -37,6 +42,8 @@ "embla-carousel-autoplay": "^8.5.2", "embla-carousel-react": "^8.5.2", "html-react-parser": "^5.2.2", + "intl-parse-accept-language": "^1.0.0", + "is-ip": "^5.0.1", "isbot": "^5.1.17", "jose": "^6.0.8", "react": "^19.0.0", @@ -49,6 +56,7 @@ "react-router": "^7.1.3", "react-share": "^5.2.2", "remix-hook-form": "^6.1.3", + "remix-utils": "^8.5.0", "string-strip-html": "^13.4.12", "tailwind-merge": "^3.0.1", "xior": "^0.6.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 28c5478..8b2135e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,15 @@ importers: .: dependencies: + '@edgefirst-dev/batcher': + specifier: ^1.0.1 + version: 1.0.1 + '@edgefirst-dev/jwt': + specifier: ^1.2.0 + version: 1.2.0 + '@edgefirst-dev/server-timing': + specifier: ^0.0.1 + version: 0.0.1 '@headlessui/react': specifier: ^2.2.0 version: 2.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -20,6 +29,12 @@ importers: '@monaco-editor/react': specifier: ^4.7.0 version: 4.7.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@oslojs/crypto': + specifier: ^1.0.1 + version: 1.0.1 + '@oslojs/encoding': + specifier: ^1.1.0 + version: 1.1.0 '@react-router/fs-routes': specifier: ^7.1.3 version: 7.1.3(@react-router/dev@7.1.3(@react-router/serve@7.1.3(react-router@7.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(typescript@5.7.3))(@types/node@20.17.16)(babel-plugin-macros@3.1.0)(lightningcss@1.29.1)(react-router@7.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(typescript@5.7.3)(vite@5.4.14(@types/node@20.17.16)(lightningcss@1.29.1)))(typescript@5.7.3) @@ -77,6 +92,12 @@ importers: html-react-parser: specifier: ^5.2.2 version: 5.2.2(@types/react@19.0.8)(react@19.0.0) + intl-parse-accept-language: + specifier: ^1.0.0 + version: 1.0.0 + is-ip: + specifier: ^5.0.1 + version: 5.0.1 isbot: specifier: ^5.1.17 version: 5.1.22 @@ -113,6 +134,9 @@ importers: remix-hook-form: specifier: ^6.1.3 version: 6.1.3(react-dom@19.0.0(react@19.0.0))(react-hook-form@7.54.2(react@19.0.0))(react-router@7.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) + remix-utils: + specifier: ^8.5.0 + version: 8.5.0(@edgefirst-dev/batcher@1.0.1)(@edgefirst-dev/jwt@1.2.0)(@edgefirst-dev/server-timing@0.0.1)(@oslojs/crypto@1.0.1)(@oslojs/encoding@1.1.0)(intl-parse-accept-language@1.0.0)(is-ip@5.0.1)(react-router@7.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(zod@3.24.2) string-strip-html: specifier: ^13.4.12 version: 13.4.12 @@ -448,6 +472,22 @@ packages: resolution: {integrity: sha512-DSHae2obMSMkAtTBSOulg5X7/z+rGLxcXQIkg3OmWvY6wifojge5uVMydfhUvs7yQj+V7jNmRZ2Xzl8GJyqRgg==} engines: {node: '>=v18'} + '@edgefirst-dev/batcher@1.0.1': + resolution: {integrity: sha512-9AsnqLSIbO0mK7Du6lRp3v7hCJuercNo7t16leZeMCnI3QReZDE2IEtbLpDwrIrcOS7xt1vgdonKYU9GQqittw==} + engines: {node: '>=20.0.0'} + + '@edgefirst-dev/data@0.0.4': + resolution: {integrity: sha512-VLhlvEPDJ0Sd0pE6sAYTQkIqZCXVonaWlgRJIQQHzfjTXCadF77qqHj5NxaPSc4wCul0DJO/0MnejVqJAXUiRg==} + engines: {node: '>=20.0.0'} + + '@edgefirst-dev/jwt@1.2.0': + resolution: {integrity: sha512-MnNceBAmJYhoctIAGYivh0/sSsKYXfEPfwGZ8tsoX96+vSRuoeLrBi4p2L9NHCjqxMafd4KMKk+93SfX3sW7dQ==} + engines: {node: '>=20.0.0'} + + '@edgefirst-dev/server-timing@0.0.1': + resolution: {integrity: sha512-WlvF/dhgM7CE9SOb3Ji6Wj4PsIk21CHvXzRVdQwmeS1eVEVimWqagiYuV5e8/7Owt7SDFpeVnuF0q2CtONch0g==} + engines: {node: '>=20.0.0'} + '@emotion/babel-plugin@11.13.5': resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} @@ -747,6 +787,12 @@ packages: '@kurkle/color@0.3.4': resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} + '@mjackson/file-storage@0.6.1': + resolution: {integrity: sha512-H3GEVpmfmNryNoYloddIOba5OAwckfVGMvutPeI94Shbv/R+NVh89gIYa8SK3Vfa+ky9PitclP+5XQ6/zlSdQQ==} + + '@mjackson/lazy-file@3.3.1': + resolution: {integrity: sha512-BxpNT1KmLx0OLYfgQESx/AKGD2czwfZXh9c0SaDUQY2DRAaVYtAvSQE5EkpATFdQQKqfL+iXVoaQ/SN+w7/CDA==} + '@mjackson/node-fetch-server@0.2.0': resolution: {integrity: sha512-EMlH1e30yzmTpGLQjlFmaDAjyOeZhng1/XCd7DExR8PNAnG/G1tyruZxEoUe11ClnwGhGrtsdnyyUx1frSzjng==} @@ -803,6 +849,18 @@ packages: '@one-ini/wasm@0.1.1': resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + '@oslojs/asn1@1.0.0': + resolution: {integrity: sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA==} + + '@oslojs/binary@1.0.0': + resolution: {integrity: sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ==} + + '@oslojs/crypto@1.0.1': + resolution: {integrity: sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ==} + + '@oslojs/encoding@1.1.0': + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -2001,6 +2059,10 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + clone-regexp@3.0.0: + resolution: {integrity: sha512-ujdnoq2Kxb8s3ItNBtnYeXdm07FcU0u8ARAT1lQ2YdMwQC+cdiXX8KoqMVuglztILivceTtp4ivqGSmEmhBUJw==} + engines: {node: '>=12'} + clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} @@ -2081,6 +2143,10 @@ packages: engines: {node: '>=16'} hasBin: true + convert-hrtime@5.0.0: + resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==} + engines: {node: '>=12'} + convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} @@ -2712,6 +2778,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + function-timeout@0.1.1: + resolution: {integrity: sha512-0NVVC0TaP7dSTvn1yMiy6d6Q8gifzbvQafO46RtLG/kHJUBNd+pVRGOBoK44wNBvtSPUJRfdVvkFdD3p0xvyZg==} + engines: {node: '>=14.16'} + function.prototype.name@1.1.8: resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} engines: {node: '>= 0.4'} @@ -2937,6 +3007,14 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + intl-parse-accept-language@1.0.0: + resolution: {integrity: sha512-YFMSV91JNBOSjw1cOfw2tup6hDP7mkz+2AUV7W1L1AM6ntgI75qC1ZeFpjPGMrWp+upmBRTX2fJWQ8c7jsUWpA==} + engines: {node: '>=14'} + + ip-regex@5.0.0: + resolution: {integrity: sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -3018,6 +3096,10 @@ packages: resolution: {integrity: sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ==} engines: {node: '>=0.10.0'} + is-ip@5.0.1: + resolution: {integrity: sha512-FCsGHdlrOnZQcp0+XT5a+pYowf33itBalCl+7ovNXC/7o5BhIpG14M3OrpPPdBSIQJCm+0M5+9mO7S9VVTTCFw==} + engines: {node: '>=14.16'} + is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} @@ -3042,6 +3124,10 @@ packages: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} + is-regexp@3.1.0: + resolution: {integrity: sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==} + engines: {node: '>=12'} + is-set@2.0.3: resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} engines: {node: '>= 0.4'} @@ -3463,6 +3549,10 @@ packages: motion-utils@11.18.1: resolution: {integrity: sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==} + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -4096,6 +4186,42 @@ packages: react-hook-form: ^7.51.0 react-router: '>=7.0.0' + remix-utils@8.5.0: + resolution: {integrity: sha512-Wf9OGSJveBaVHKptbEgxc+DwKRUUGOH+aiaBlsrAA2b4F+gNtCkvaZzA7Tp+1esBElRcRvMZQq/0aSSWFMP18A==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@edgefirst-dev/batcher': ^1.0.0 + '@edgefirst-dev/jwt': ^1.2.0 + '@edgefirst-dev/server-timing': ^0.0.1 + '@oslojs/crypto': ^1.0.1 + '@oslojs/encoding': ^1.1.0 + intl-parse-accept-language: ^1.0.0 + is-ip: ^5.0.1 + react: ^18.0.0 || ^19.0.0 + react-router: ^7.0.0 + zod: ^3.22.4 + peerDependenciesMeta: + '@edgefirst-dev/batcher': + optional: true + '@edgefirst-dev/jwt': + optional: true + '@edgefirst-dev/server-timing': + optional: true + '@oslojs/crypto': + optional: true + '@oslojs/encoding': + optional: true + intl-parse-accept-language: + optional: true + is-ip: + optional: true + react: + optional: true + react-router: + optional: true + zod: + optional: true + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -4403,6 +4529,10 @@ packages: summary@2.1.0: resolution: {integrity: sha512-nMIjMrd5Z2nuB2RZCKJfFMjgS3fygbeyGk9PxPPaJR1RIcyN9yn4A63Isovzm3ZtQuEkLBVgMdPup8UeLH7aQw==} + super-regex@0.2.0: + resolution: {integrity: sha512-WZzIx3rC1CvbMDloLsVw0lkZVKJWbrkJ0k1ghKFmcnPrW1+jWbgTkTEWVtD9lMdmI4jZEz40+naBxl1dCUhXXw==} + engines: {node: '>=14.16'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -4437,6 +4567,10 @@ packages: through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + time-span@5.1.0: + resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} + engines: {node: '>=12'} + tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -4507,6 +4641,10 @@ packages: resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} engines: {node: '>=8'} + type-fest@4.37.0: + resolution: {integrity: sha512-S/5/0kFftkq27FPNye0XM1e2NsnoD/3FS+pBmbjmmtLT6I+i344KoOf7pvXreaFsDamWeaJX55nczA1m5PsBDg==} + engines: {node: '>=16'} + type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -5105,6 +5243,21 @@ snapshots: '@types/conventional-commits-parser': 5.0.1 chalk: 5.4.1 + '@edgefirst-dev/batcher@1.0.1': + dependencies: + type-fest: 4.37.0 + + '@edgefirst-dev/data@0.0.4': {} + + '@edgefirst-dev/jwt@1.2.0': + dependencies: + '@edgefirst-dev/data': 0.0.4 + '@mjackson/file-storage': 0.6.1 + jose: 6.0.8 + type-fest: 4.37.0 + + '@edgefirst-dev/server-timing@0.0.1': {} + '@emotion/babel-plugin@11.13.5': dependencies: '@babel/helper-module-imports': 7.25.9 @@ -5391,6 +5544,14 @@ snapshots: '@kurkle/color@0.3.4': {} + '@mjackson/file-storage@0.6.1': + dependencies: + '@mjackson/lazy-file': 3.3.1 + + '@mjackson/lazy-file@3.3.1': + dependencies: + mrmime: 2.0.1 + '@mjackson/node-fetch-server@0.2.0': {} '@monaco-editor/loader@1.5.0': @@ -5461,6 +5622,19 @@ snapshots: '@one-ini/wasm@0.1.1': {} + '@oslojs/asn1@1.0.0': + dependencies: + '@oslojs/binary': 1.0.0 + + '@oslojs/binary@1.0.0': {} + + '@oslojs/crypto@1.0.1': + dependencies: + '@oslojs/asn1': 1.0.0 + '@oslojs/binary': 1.0.0 + + '@oslojs/encoding@1.1.0': {} + '@pkgjs/parseargs@0.11.0': optional: true @@ -6698,6 +6872,10 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + clone-regexp@3.0.0: + dependencies: + is-regexp: 3.1.0 + clone@1.0.4: optional: true @@ -6779,6 +6957,8 @@ snapshots: meow: 12.1.1 split2: 4.2.0 + convert-hrtime@5.0.0: {} + convert-source-map@1.9.0: {} convert-source-map@2.0.0: {} @@ -7576,6 +7756,8 @@ snapshots: function-bind@1.1.2: {} + function-timeout@0.1.1: {} + function.prototype.name@1.1.8: dependencies: call-bind: 1.0.8 @@ -7805,6 +7987,10 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 + intl-parse-accept-language@1.0.0: {} + + ip-regex@5.0.0: {} + ipaddr.js@1.9.1: {} is-array-buffer@3.0.5: @@ -7886,6 +8072,11 @@ snapshots: is-gzip@1.0.0: {} + is-ip@5.0.1: + dependencies: + ip-regex: 5.0.0 + super-regex: 0.2.0 + is-map@2.0.3: {} is-number-object@1.1.1: @@ -7906,6 +8097,8 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 + is-regexp@3.1.0: {} + is-set@2.0.3: {} is-shared-array-buffer@1.0.4: @@ -8291,6 +8484,8 @@ snapshots: motion-utils@11.18.1: {} + mrmime@2.0.1: {} + ms@2.0.0: {} ms@2.1.3: {} @@ -8936,6 +9131,21 @@ snapshots: react-hook-form: 7.54.2(react@19.0.0) react-router: 7.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + remix-utils@8.5.0(@edgefirst-dev/batcher@1.0.1)(@edgefirst-dev/jwt@1.2.0)(@edgefirst-dev/server-timing@0.0.1)(@oslojs/crypto@1.0.1)(@oslojs/encoding@1.1.0)(intl-parse-accept-language@1.0.0)(is-ip@5.0.1)(react-router@7.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(zod@3.24.2): + dependencies: + type-fest: 4.37.0 + optionalDependencies: + '@edgefirst-dev/batcher': 1.0.1 + '@edgefirst-dev/jwt': 1.2.0 + '@edgefirst-dev/server-timing': 0.0.1 + '@oslojs/crypto': 1.0.1 + '@oslojs/encoding': 1.1.0 + intl-parse-accept-language: 1.0.0 + is-ip: 5.0.1 + react: 19.0.0 + react-router: 7.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + zod: 3.24.2 + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -9300,6 +9510,12 @@ snapshots: summary@2.1.0: {} + super-regex@0.2.0: + dependencies: + clone-regexp: 3.0.0 + function-timeout: 0.1.1 + time-span: 5.1.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -9325,6 +9541,10 @@ snapshots: through@2.3.8: {} + time-span@5.1.0: + dependencies: + convert-hrtime: 5.0.0 + tiny-invariant@1.3.3: {} tiny-lru@11.2.11: {} @@ -9377,6 +9597,8 @@ snapshots: type-fest@0.8.1: {} + type-fest@4.37.0: {} + type-is@1.6.18: dependencies: media-typer: 0.3.0