report errors to sentry
This commit is contained in:
parent
590e92eea4
commit
961dc8e461
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,7 +5,7 @@ node_modules
|
|||||||
/public/build
|
/public/build
|
||||||
/public/entry.worker.js
|
/public/entry.worker.js
|
||||||
/build
|
/build
|
||||||
server.js
|
/server/index.js
|
||||||
/app/styles/tailwind.css
|
/app/styles/tailwind.css
|
||||||
|
|
||||||
/.idea
|
/.idea
|
||||||
|
@ -36,6 +36,7 @@ invariant(
|
|||||||
typeof process.env.WEB_PUSH_VAPID_PUBLIC_KEY === "string",
|
typeof process.env.WEB_PUSH_VAPID_PUBLIC_KEY === "string",
|
||||||
`Please define the "WEB_PUSH_VAPID_PUBLIC_KEY" environment variable`,
|
`Please define the "WEB_PUSH_VAPID_PUBLIC_KEY" environment variable`,
|
||||||
);
|
);
|
||||||
|
invariant(typeof process.env.SENTRY_DSN === "string", `Please define the "SENTRY_DSN" environment variable`);
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
app: {
|
app: {
|
||||||
@ -54,6 +55,9 @@ export default {
|
|||||||
url: process.env.REDIS_URL,
|
url: process.env.REDIS_URL,
|
||||||
password: process.env.REDIS_PASSWORD,
|
password: process.env.REDIS_PASSWORD,
|
||||||
},
|
},
|
||||||
|
sentry: {
|
||||||
|
dsn: process.env.SENTRY_DSN,
|
||||||
|
},
|
||||||
twilio: {
|
twilio: {
|
||||||
authToken: process.env.TWILIO_AUTH_TOKEN,
|
authToken: process.env.TWILIO_AUTH_TOKEN,
|
||||||
},
|
},
|
||||||
|
@ -1,5 +1,21 @@
|
|||||||
import { hydrate } from "react-dom";
|
import { hydrate } from "react-dom";
|
||||||
import { RemixBrowser } from "@remix-run/react";
|
import { RemixBrowser } from "@remix-run/react";
|
||||||
|
import * as Sentry from "@sentry/browser";
|
||||||
|
import { Integrations } from "@sentry/tracing";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
shellphoneConfig: {
|
||||||
|
sentry: { dsn: string };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Sentry.init({
|
||||||
|
dsn: window.shellphoneConfig.sentry.dsn,
|
||||||
|
tracesSampleRate: 1.0,
|
||||||
|
integrations: [new Integrations.BrowserTracing()],
|
||||||
|
});
|
||||||
|
|
||||||
hydrate(<RemixBrowser />, document);
|
hydrate(<RemixBrowser />, document);
|
||||||
|
|
||||||
|
35
app/root.tsx
35
app/root.tsx
@ -1,17 +1,48 @@
|
|||||||
import type { FunctionComponent, PropsWithChildren } from "react";
|
import type { FunctionComponent, PropsWithChildren } from "react";
|
||||||
import type { LinksFunction } from "@remix-run/node";
|
import { type LinksFunction, type LoaderFunction, json } from "@remix-run/node";
|
||||||
import { Link, Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration, useCatch } from "@remix-run/react";
|
import {
|
||||||
|
Link,
|
||||||
|
Links,
|
||||||
|
LiveReload,
|
||||||
|
Meta,
|
||||||
|
Outlet,
|
||||||
|
Scripts,
|
||||||
|
ScrollRestoration,
|
||||||
|
useCatch,
|
||||||
|
useLoaderData,
|
||||||
|
} from "@remix-run/react";
|
||||||
|
|
||||||
|
import config from "~/config/config.server";
|
||||||
import Logo from "~/features/core/components/logo";
|
import Logo from "~/features/core/components/logo";
|
||||||
|
|
||||||
import styles from "./styles/tailwind.css";
|
import styles from "./styles/tailwind.css";
|
||||||
|
|
||||||
export const links: LinksFunction = () => [{ rel: "stylesheet", href: styles }];
|
export const links: LinksFunction = () => [{ rel: "stylesheet", href: styles }];
|
||||||
|
|
||||||
|
type LoaderData = {
|
||||||
|
shellphoneConfig: string;
|
||||||
|
};
|
||||||
|
export const loader: LoaderFunction = () => {
|
||||||
|
return json<LoaderData>({
|
||||||
|
shellphoneConfig: JSON.stringify({
|
||||||
|
sentry: {
|
||||||
|
dsn: config.sentry.dsn,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
|
const { shellphoneConfig } = useLoaderData<LoaderData>();
|
||||||
return (
|
return (
|
||||||
<Document>
|
<Document>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
|
<script
|
||||||
|
suppressHydrationWarning
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: `window.shellphoneConfig=${shellphoneConfig};`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Document>
|
</Document>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { type LinksFunction, type LoaderFunction, json } from "@remix-run/node";
|
import { type LinksFunction, type LoaderFunction, json } from "@remix-run/node";
|
||||||
import { Outlet, useCatch, useMatches } from "@remix-run/react";
|
import { Outlet, useCatch, useLoaderData, useMatches } from "@remix-run/react";
|
||||||
|
import * as Sentry from "@sentry/browser";
|
||||||
|
|
||||||
import serverConfig from "~/config/config.server";
|
import serverConfig from "~/config/config.server";
|
||||||
import { type SessionData, requireLoggedIn } from "~/utils/auth.server";
|
import { type SessionData, requireLoggedIn } from "~/utils/auth.server";
|
||||||
@ -10,6 +11,7 @@ import useServiceWorkerRevalidate from "~/features/core/hooks/use-service-worker
|
|||||||
import useDevice from "~/features/phone-calls/hooks/use-device";
|
import useDevice from "~/features/phone-calls/hooks/use-device";
|
||||||
import footerStyles from "~/features/core/components/footer.css";
|
import footerStyles from "~/features/core/components/footer.css";
|
||||||
import appStyles from "~/styles/app.css";
|
import appStyles from "~/styles/app.css";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
export const links: LinksFunction = () => [
|
export const links: LinksFunction = () => [
|
||||||
{ rel: "stylesheet", href: appStyles },
|
{ rel: "stylesheet", href: appStyles },
|
||||||
@ -35,9 +37,14 @@ export const loader: LoaderFunction = async ({ request }) => {
|
|||||||
export default function __App() {
|
export default function __App() {
|
||||||
useDevice();
|
useDevice();
|
||||||
useServiceWorkerRevalidate();
|
useServiceWorkerRevalidate();
|
||||||
|
const { sessionData } = useLoaderData<AppLoaderData>();
|
||||||
const matches = useMatches();
|
const matches = useMatches();
|
||||||
const hideFooter = matches.some((match) => match.handle?.hideFooter === true);
|
const hideFooter = matches.some((match) => match.handle?.hideFooter === true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Sentry.setUser(sessionData.user);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="h-full w-full overflow-hidden fixed bg-gray-100">
|
<div className="h-full w-full overflow-hidden fixed bg-gray-100">
|
||||||
|
290
package-lock.json
generated
290
package-lock.json
generated
@ -14,6 +14,9 @@
|
|||||||
"@remix-run/express": "1.5.1",
|
"@remix-run/express": "1.5.1",
|
||||||
"@remix-run/node": "1.5.1",
|
"@remix-run/node": "1.5.1",
|
||||||
"@remix-run/react": "1.5.1",
|
"@remix-run/react": "1.5.1",
|
||||||
|
"@sentry/browser": "7.3.0",
|
||||||
|
"@sentry/node": "7.3.0",
|
||||||
|
"@sentry/tracing": "7.3.0",
|
||||||
"@tailwindcss/forms": "0.5.2",
|
"@tailwindcss/forms": "0.5.2",
|
||||||
"@tailwindcss/line-clamp": "0.4.0",
|
"@tailwindcss/line-clamp": "0.4.0",
|
||||||
"@tailwindcss/typography": "0.5.2",
|
"@tailwindcss/typography": "0.5.2",
|
||||||
@ -46,6 +49,7 @@
|
|||||||
"tiny-invariant": "1.2.0",
|
"tiny-invariant": "1.2.0",
|
||||||
"tslog": "3.3.3",
|
"tslog": "3.3.3",
|
||||||
"twilio": "3.77.1",
|
"twilio": "3.77.1",
|
||||||
|
"uuid": "8.3.2",
|
||||||
"web-push": "3.5.0",
|
"web-push": "3.5.0",
|
||||||
"zod": "3.17.3"
|
"zod": "3.17.3"
|
||||||
},
|
},
|
||||||
@ -66,6 +70,7 @@
|
|||||||
"@types/react": "18.0.10",
|
"@types/react": "18.0.10",
|
||||||
"@types/react-dom": "18.0.5",
|
"@types/react-dom": "18.0.5",
|
||||||
"@types/secure-password": "3.1.1",
|
"@types/secure-password": "3.1.1",
|
||||||
|
"@types/uuid": "8.3.4",
|
||||||
"@types/web-push": "3.3.2",
|
"@types/web-push": "3.3.2",
|
||||||
"@vitejs/plugin-react": "1.3.2",
|
"@vitejs/plugin-react": "1.3.2",
|
||||||
"c8": "7.11.3",
|
"c8": "7.11.3",
|
||||||
@ -2533,15 +2538,6 @@
|
|||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cypress/request/node_modules/uuid": {
|
|
||||||
"version": "8.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
|
||||||
"dev": true,
|
|
||||||
"bin": {
|
|
||||||
"uuid": "dist/bin/uuid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@cypress/xvfb": {
|
"node_modules/@cypress/xvfb": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz",
|
||||||
@ -3994,6 +3990,99 @@
|
|||||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@sentry/browser": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-UJMTDbajKNRGrs4ZQNelrPDaATvSZ9uELpPOtPSG6JUvB1BCwGgsgzz55RS0Uqs7B8KhMnDQ0kIn3FMewM4FMg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/core": "7.3.0",
|
||||||
|
"@sentry/types": "7.3.0",
|
||||||
|
"@sentry/utils": "7.3.0",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/core": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-EvuWVlYm0F0+BtIEmQiCL31Fw0cfKSwUTmxc99wvouaabpHBr2zCJHRxaXOWzxS705bYBJEQiFDTIHfoOQZMzA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/hub": "7.3.0",
|
||||||
|
"@sentry/types": "7.3.0",
|
||||||
|
"@sentry/utils": "7.3.0",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/hub": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-0GtTaWf/hoAMoIFY7Ke6eozIbG3FdIPM364sER4SxUQVSklp6AORrV6p82IgWPROK6aj83cPk9Bszgi6RiF/BA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/types": "7.3.0",
|
||||||
|
"@sentry/utils": "7.3.0",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/node": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-hPqLQMdpL9MeirtKDCgy0ekptWh58CCUhvcoQ2bYstVBsyMMTNTbiQqF/ClzanrScQ5CEuGWnCbKxrFN/S6cQg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/core": "7.3.0",
|
||||||
|
"@sentry/hub": "7.3.0",
|
||||||
|
"@sentry/types": "7.3.0",
|
||||||
|
"@sentry/utils": "7.3.0",
|
||||||
|
"cookie": "^0.4.1",
|
||||||
|
"https-proxy-agent": "^5.0.0",
|
||||||
|
"lru_map": "^0.3.3",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/tracing": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-A+mLEH8jtLkhfyw81EZA1XgI96jh9TIwH9EST3hdfSPgdZQf0A5sV8oVVh/d9Hw7NVb65Va5KhAZDNhcx5QxUA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/hub": "7.3.0",
|
||||||
|
"@sentry/types": "7.3.0",
|
||||||
|
"@sentry/utils": "7.3.0",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/types": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-cGkHdh9+uvbFTj65TjWcXuhe6vQiMY+U+N2GE5xCfmZT9hwuouCASViNsbJMpZqvCg+Yi0fasQLZ71rujiRNOA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/utils": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-xUP8TBf2p/c6CN8eFQ7Y+xk0IFrJXsph5ScozqNl/2l/Xs8hd2EiYETqgUklphoYD4J2RxvPwMyqBL15QN6wNg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/types": "7.3.0",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@sideway/address": {
|
"node_modules/@sideway/address": {
|
||||||
"version": "4.1.4",
|
"version": "4.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
|
||||||
@ -4627,6 +4716,12 @@
|
|||||||
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==",
|
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/uuid": {
|
||||||
|
"version": "8.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
|
||||||
|
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/web-push": {
|
"node_modules/@types/web-push": {
|
||||||
"version": "3.3.2",
|
"version": "3.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/web-push/-/web-push-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/web-push/-/web-push-3.3.2.tgz",
|
||||||
@ -5463,6 +5558,14 @@
|
|||||||
"node": ">= 10.0.0"
|
"node": ">= 10.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/aws-sdk/node_modules/uuid": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==",
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/aws-sign2": {
|
"node_modules/aws-sign2": {
|
||||||
"version": "0.7.0",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||||
@ -6094,14 +6197,6 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/bullmq/node_modules/uuid": {
|
|
||||||
"version": "8.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
|
||||||
"bin": {
|
|
||||||
"uuid": "dist/bin/uuid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/bytes": {
|
"node_modules/bytes": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
||||||
@ -13723,6 +13818,11 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lru_map": {
|
||||||
|
"version": "0.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz",
|
||||||
|
"integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ=="
|
||||||
|
},
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
@ -17677,14 +17777,6 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/preview-email/node_modules/uuid": {
|
|
||||||
"version": "8.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
|
||||||
"bin": {
|
|
||||||
"uuid": "dist/bin/uuid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/prisma": {
|
"node_modules/prisma": {
|
||||||
"version": "3.14.0",
|
"version": "3.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-3.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/prisma/-/prisma-3.14.0.tgz",
|
||||||
@ -18760,14 +18852,6 @@
|
|||||||
"@remix-run/server-runtime": "^1.0.0"
|
"@remix-run/server-runtime": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/remix-auth/node_modules/uuid": {
|
|
||||||
"version": "8.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
|
||||||
"bin": {
|
|
||||||
"uuid": "dist/bin/uuid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/remix-seo": {
|
"node_modules/remix-seo": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/remix-seo/-/remix-seo-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/remix-seo/-/remix-seo-0.1.0.tgz",
|
||||||
@ -18811,14 +18895,6 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/remix-utils/node_modules/uuid": {
|
|
||||||
"version": "8.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
|
||||||
"bin": {
|
|
||||||
"uuid": "dist/bin/uuid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/repeat-element": {
|
"node_modules/repeat-element": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
|
||||||
@ -21849,9 +21925,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/uuid": {
|
"node_modules/uuid": {
|
||||||
"version": "8.0.0",
|
"version": "8.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
"integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==",
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
@ -24448,12 +24524,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
|
||||||
"integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
|
"integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
|
||||||
"uuid": {
|
|
||||||
"version": "8.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
|
||||||
"dev": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -25482,6 +25552,78 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@sentry/browser": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-UJMTDbajKNRGrs4ZQNelrPDaATvSZ9uELpPOtPSG6JUvB1BCwGgsgzz55RS0Uqs7B8KhMnDQ0kIn3FMewM4FMg==",
|
||||||
|
"requires": {
|
||||||
|
"@sentry/core": "7.3.0",
|
||||||
|
"@sentry/types": "7.3.0",
|
||||||
|
"@sentry/utils": "7.3.0",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@sentry/core": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-EvuWVlYm0F0+BtIEmQiCL31Fw0cfKSwUTmxc99wvouaabpHBr2zCJHRxaXOWzxS705bYBJEQiFDTIHfoOQZMzA==",
|
||||||
|
"requires": {
|
||||||
|
"@sentry/hub": "7.3.0",
|
||||||
|
"@sentry/types": "7.3.0",
|
||||||
|
"@sentry/utils": "7.3.0",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@sentry/hub": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-0GtTaWf/hoAMoIFY7Ke6eozIbG3FdIPM364sER4SxUQVSklp6AORrV6p82IgWPROK6aj83cPk9Bszgi6RiF/BA==",
|
||||||
|
"requires": {
|
||||||
|
"@sentry/types": "7.3.0",
|
||||||
|
"@sentry/utils": "7.3.0",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@sentry/node": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-hPqLQMdpL9MeirtKDCgy0ekptWh58CCUhvcoQ2bYstVBsyMMTNTbiQqF/ClzanrScQ5CEuGWnCbKxrFN/S6cQg==",
|
||||||
|
"requires": {
|
||||||
|
"@sentry/core": "7.3.0",
|
||||||
|
"@sentry/hub": "7.3.0",
|
||||||
|
"@sentry/types": "7.3.0",
|
||||||
|
"@sentry/utils": "7.3.0",
|
||||||
|
"cookie": "^0.4.1",
|
||||||
|
"https-proxy-agent": "^5.0.0",
|
||||||
|
"lru_map": "^0.3.3",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@sentry/tracing": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-A+mLEH8jtLkhfyw81EZA1XgI96jh9TIwH9EST3hdfSPgdZQf0A5sV8oVVh/d9Hw7NVb65Va5KhAZDNhcx5QxUA==",
|
||||||
|
"requires": {
|
||||||
|
"@sentry/hub": "7.3.0",
|
||||||
|
"@sentry/types": "7.3.0",
|
||||||
|
"@sentry/utils": "7.3.0",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@sentry/types": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-cGkHdh9+uvbFTj65TjWcXuhe6vQiMY+U+N2GE5xCfmZT9hwuouCASViNsbJMpZqvCg+Yi0fasQLZ71rujiRNOA=="
|
||||||
|
},
|
||||||
|
"@sentry/utils": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-xUP8TBf2p/c6CN8eFQ7Y+xk0IFrJXsph5ScozqNl/2l/Xs8hd2EiYETqgUklphoYD4J2RxvPwMyqBL15QN6wNg==",
|
||||||
|
"requires": {
|
||||||
|
"@sentry/types": "7.3.0",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@sideway/address": {
|
"@sideway/address": {
|
||||||
"version": "4.1.4",
|
"version": "4.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
|
||||||
@ -26054,6 +26196,12 @@
|
|||||||
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==",
|
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/uuid": {
|
||||||
|
"version": "8.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
|
||||||
|
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/web-push": {
|
"@types/web-push": {
|
||||||
"version": "3.3.2",
|
"version": "3.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/web-push/-/web-push-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/web-push/-/web-push-3.3.2.tgz",
|
||||||
@ -26623,6 +26771,13 @@
|
|||||||
"url": "0.10.3",
|
"url": "0.10.3",
|
||||||
"uuid": "8.0.0",
|
"uuid": "8.0.0",
|
||||||
"xml2js": "0.4.19"
|
"xml2js": "0.4.19"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"uuid": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"aws-sign2": {
|
"aws-sign2": {
|
||||||
@ -27131,11 +27286,6 @@
|
|||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
|
||||||
"integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw=="
|
"integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw=="
|
||||||
},
|
|
||||||
"uuid": {
|
|
||||||
"version": "8.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -32775,6 +32925,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
|
||||||
"integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="
|
"integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="
|
||||||
},
|
},
|
||||||
|
"lru_map": {
|
||||||
|
"version": "0.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz",
|
||||||
|
"integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ=="
|
||||||
|
},
|
||||||
"lru-cache": {
|
"lru-cache": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
@ -35565,13 +35720,6 @@
|
|||||||
"open": "7",
|
"open": "7",
|
||||||
"pug": "^3.0.2",
|
"pug": "^3.0.2",
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^8.3.2"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"uuid": {
|
|
||||||
"version": "8.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"prisma": {
|
"prisma": {
|
||||||
@ -36434,13 +36582,6 @@
|
|||||||
"integrity": "sha512-VtzkfxeXbnXilupRTZkP40aik4vFSdwwRT96mbq0UBDMqHVRfQ7h9Y51HFrTufHJZEfAdkCopedMVvm0vQYKag==",
|
"integrity": "sha512-VtzkfxeXbnXilupRTZkP40aik4vFSdwwRT96mbq0UBDMqHVRfQ7h9Y51HFrTufHJZEfAdkCopedMVvm0vQYKag==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^8.3.2"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"uuid": {
|
|
||||||
"version": "8.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"remix-auth-form": {
|
"remix-auth-form": {
|
||||||
@ -36475,11 +36616,6 @@
|
|||||||
"version": "2.13.0",
|
"version": "2.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.13.0.tgz",
|
||||||
"integrity": "sha512-lPfAm42MxE4/456+QyIaaVBAwgpJb6xZ8PRu09utnhPdWwcyj9vgy6Sq0Z5yNbJ21EdxB5dRU/Qg8bsyAMtlcw=="
|
"integrity": "sha512-lPfAm42MxE4/456+QyIaaVBAwgpJb6xZ8PRu09utnhPdWwcyj9vgy6Sq0Z5yNbJ21EdxB5dRU/Qg8bsyAMtlcw=="
|
||||||
},
|
|
||||||
"uuid": {
|
|
||||||
"version": "8.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -38914,9 +39050,9 @@
|
|||||||
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
|
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
|
||||||
},
|
},
|
||||||
"uuid": {
|
"uuid": {
|
||||||
"version": "8.0.0",
|
"version": "8.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
"integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw=="
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||||
},
|
},
|
||||||
"uvu": {
|
"uvu": {
|
||||||
"version": "0.5.3",
|
"version": "0.5.3",
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
"dev:build": "NODE_ENV=development dotenv npm run build:server -- -- --watch",
|
"dev:build": "NODE_ENV=development dotenv npm run build:server -- -- --watch",
|
||||||
"dev:css": "NODE_ENV=development tailwindcss -i ./styles/tailwind.css -o ./app/styles/tailwind.css --watch",
|
"dev:css": "NODE_ENV=development tailwindcss -i ./styles/tailwind.css -o ./app/styles/tailwind.css --watch",
|
||||||
"dev:remix": "NODE_ENV=development remix watch",
|
"dev:remix": "NODE_ENV=development remix watch",
|
||||||
"dev:server": "NODE_ENV=development dotenv node ./server.js",
|
"dev:server": "NODE_ENV=development dotenv node ./server/index.js",
|
||||||
"dev:worker": "NODE_ENV=development npm run build:worker -- --watch",
|
"dev:worker": "NODE_ENV=development npm run build:worker -- --watch",
|
||||||
"dev:init": "NODE_ENV=development dotenv run-s build:remix build:server",
|
"dev:init": "NODE_ENV=development dotenv run-s build:remix build:server",
|
||||||
"dev": "npm run dev:init && run-p dev:build dev:worker dev:css dev:remix dev:server",
|
"dev": "npm run dev:init && run-p dev:build dev:worker dev:css dev:remix dev:server",
|
||||||
@ -15,7 +15,7 @@
|
|||||||
"build:remix": "remix build",
|
"build:remix": "remix build",
|
||||||
"build:worker": "node ./scripts/build-worker.js",
|
"build:worker": "node ./scripts/build-worker.js",
|
||||||
"build": "NODE_ENV=production run-s build:css build:remix build:worker build:server",
|
"build": "NODE_ENV=production run-s build:css build:remix build:worker build:server",
|
||||||
"start": "NODE_ENV=production node ./server.js",
|
"start": "NODE_ENV=production node ./server/index.js",
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
"test:coverage": "vitest run --coverage",
|
"test:coverage": "vitest run --coverage",
|
||||||
"lint": "eslint --ignore-path .gitignore --ext .js,.ts,.tsx .",
|
"lint": "eslint --ignore-path .gitignore --ext .js,.ts,.tsx .",
|
||||||
@ -57,6 +57,9 @@
|
|||||||
"@remix-run/express": "1.5.1",
|
"@remix-run/express": "1.5.1",
|
||||||
"@remix-run/node": "1.5.1",
|
"@remix-run/node": "1.5.1",
|
||||||
"@remix-run/react": "1.5.1",
|
"@remix-run/react": "1.5.1",
|
||||||
|
"@sentry/browser": "7.3.0",
|
||||||
|
"@sentry/node": "7.3.0",
|
||||||
|
"@sentry/tracing": "7.3.0",
|
||||||
"@tailwindcss/forms": "0.5.2",
|
"@tailwindcss/forms": "0.5.2",
|
||||||
"@tailwindcss/line-clamp": "0.4.0",
|
"@tailwindcss/line-clamp": "0.4.0",
|
||||||
"@tailwindcss/typography": "0.5.2",
|
"@tailwindcss/typography": "0.5.2",
|
||||||
@ -89,6 +92,7 @@
|
|||||||
"tiny-invariant": "1.2.0",
|
"tiny-invariant": "1.2.0",
|
||||||
"tslog": "3.3.3",
|
"tslog": "3.3.3",
|
||||||
"twilio": "3.77.1",
|
"twilio": "3.77.1",
|
||||||
|
"uuid": "8.3.2",
|
||||||
"web-push": "3.5.0",
|
"web-push": "3.5.0",
|
||||||
"zod": "3.17.3"
|
"zod": "3.17.3"
|
||||||
},
|
},
|
||||||
@ -109,6 +113,7 @@
|
|||||||
"@types/react": "18.0.10",
|
"@types/react": "18.0.10",
|
||||||
"@types/react-dom": "18.0.5",
|
"@types/react-dom": "18.0.5",
|
||||||
"@types/secure-password": "3.1.1",
|
"@types/secure-password": "3.1.1",
|
||||||
|
"@types/uuid": "8.3.4",
|
||||||
"@types/web-push": "3.3.2",
|
"@types/web-push": "3.3.2",
|
||||||
"@vitejs/plugin-react": "1.3.2",
|
"@vitejs/plugin-react": "1.3.2",
|
||||||
"c8": "7.11.3",
|
"c8": "7.11.3",
|
||||||
|
@ -9,8 +9,8 @@ const watch = args.includes("--watch");
|
|||||||
esbuild
|
esbuild
|
||||||
.build({
|
.build({
|
||||||
write: true,
|
write: true,
|
||||||
outfile: path.join(basePath, "server.js"),
|
outfile: path.join(basePath, "server/index.js"),
|
||||||
entryPoints: [path.join(basePath, "server.ts")],
|
entryPoints: [path.join(basePath, "server/index.ts")],
|
||||||
platform: "node",
|
platform: "node",
|
||||||
format: "cjs",
|
format: "cjs",
|
||||||
bundle: true,
|
bundle: true,
|
||||||
@ -19,7 +19,7 @@ esbuild
|
|||||||
{
|
{
|
||||||
name: "remix-bundle-external",
|
name: "remix-bundle-external",
|
||||||
setup(build) {
|
setup(build) {
|
||||||
build.onResolve({ filter: /^\.\/build$/ }, () => ({ external: true }));
|
build.onResolve({ filter: /^\.\.\/build$/ }, () => ({ external: true }));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -37,7 +37,7 @@ esbuild
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Server rebuilt successfully");
|
console.log("Server rebuilt successfully"); // TODO: find a way to restart the dev server process
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
: false,
|
: false,
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
import path from "node:path";
|
import express from "express";
|
||||||
import express, { type NextFunction, type Request, type Response } from "express";
|
|
||||||
import compression from "compression";
|
import compression from "compression";
|
||||||
import morgan from "morgan";
|
import morgan from "morgan";
|
||||||
import { createRequestHandler } from "@remix-run/express";
|
import { createRequestHandler } from "@remix-run/express";
|
||||||
import { createBullBoard } from "@bull-board/api";
|
import * as Sentry from "@sentry/node";
|
||||||
import { BullMQAdapter } from "@bull-board/api/bullMQAdapter";
|
|
||||||
import { ExpressAdapter } from "@bull-board/express";
|
|
||||||
import { GlobalRole } from "@prisma/client";
|
|
||||||
|
|
||||||
import cronJobs from "~/cron-jobs";
|
import config from "~/config/config.server";
|
||||||
import queues from "~/queues";
|
|
||||||
import logger from "~/utils/logger.server";
|
import logger from "~/utils/logger.server";
|
||||||
import { __getSession } from "~/utils/session.server";
|
import { adminMiddleware, setupBullBoard } from "./queues";
|
||||||
import { type SessionData } from "~/utils/auth.server";
|
import { registerSentry, sentryLoadContext } from "./sentry-remix";
|
||||||
|
|
||||||
|
Sentry.init({
|
||||||
|
dsn: config.sentry.dsn,
|
||||||
|
integrations: [new Sentry.Integrations.Http({ tracing: true })],
|
||||||
|
tracesSampleRate: 1.0,
|
||||||
|
environment: process.env.NODE_ENV,
|
||||||
|
});
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
@ -83,46 +85,21 @@ app.all("*", (req, res, next) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return createRequestHandler({
|
return createRequestHandler({
|
||||||
build: require("./build"),
|
build: registerSentry(require("../build")),
|
||||||
mode: process.env.NODE_ENV,
|
mode: process.env.NODE_ENV,
|
||||||
|
getLoadContext: sentryLoadContext,
|
||||||
})(req, res, next);
|
})(req, res, next);
|
||||||
});
|
});
|
||||||
|
|
||||||
const port = process.env.PORT || 3000;
|
const port = process.env.PORT || 3000;
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
require("./build"); // preload the build so we're ready for the first request
|
|
||||||
logger.info(`Server listening on port ${port}`);
|
logger.info(`Server listening on port ${port}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function adminMiddleware(req: Request, res: Response, next: NextFunction) {
|
|
||||||
const session = await __getSession(req.headers.cookie);
|
|
||||||
const sessionData: SessionData | undefined = session.data.user;
|
|
||||||
if (!sessionData || sessionData.user.role !== GlobalRole.SUPERADMIN) {
|
|
||||||
return res.setHeader("Location", "/sign-in").status(302).end();
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupBullBoard() {
|
|
||||||
const serverAdapter = new ExpressAdapter();
|
|
||||||
const cronJobsQueues = registerCronJobs();
|
|
||||||
createBullBoard({
|
|
||||||
queues: [...queues, ...cronJobsQueues].map((queue) => new BullMQAdapter(queue)),
|
|
||||||
serverAdapter,
|
|
||||||
});
|
|
||||||
serverAdapter.setBasePath("/admin/queues");
|
|
||||||
return serverAdapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerCronJobs() {
|
|
||||||
return cronJobs.map((registerCronJob) => registerCronJob());
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildDir = path.join(process.cwd(), "build");
|
|
||||||
function purgeRequireCache() {
|
function purgeRequireCache() {
|
||||||
|
const resolved = require.resolve("../build");
|
||||||
for (const key in require.cache) {
|
for (const key in require.cache) {
|
||||||
if (key.startsWith(buildDir)) {
|
if (key.startsWith(resolved)) {
|
||||||
delete require.cache[key];
|
delete require.cache[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
35
server/queues.ts
Normal file
35
server/queues.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import type { NextFunction, Request, Response } from "express";
|
||||||
|
import { ExpressAdapter } from "@bull-board/express";
|
||||||
|
import { BullMQAdapter } from "@bull-board/api/bullMQAdapter";
|
||||||
|
import { createBullBoard } from "@bull-board/api";
|
||||||
|
import { GlobalRole } from "@prisma/client";
|
||||||
|
|
||||||
|
import { __getSession } from "~/utils/session.server";
|
||||||
|
import type { SessionData } from "~/utils/auth.server";
|
||||||
|
import queues from "~/queues";
|
||||||
|
import cronJobs from "~/cron-jobs";
|
||||||
|
|
||||||
|
export async function adminMiddleware(req: Request, res: Response, next: NextFunction) {
|
||||||
|
const session = await __getSession(req.headers.cookie);
|
||||||
|
const sessionData: SessionData | undefined = session.data.user;
|
||||||
|
if (!sessionData || sessionData.user.role !== GlobalRole.SUPERADMIN) {
|
||||||
|
return res.setHeader("Location", "/sign-in").status(302).end();
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setupBullBoard() {
|
||||||
|
const serverAdapter = new ExpressAdapter();
|
||||||
|
const cronJobsQueues = registerCronJobs();
|
||||||
|
createBullBoard({
|
||||||
|
queues: [...queues, ...cronJobsQueues].map((queue) => new BullMQAdapter(queue)),
|
||||||
|
serverAdapter,
|
||||||
|
});
|
||||||
|
serverAdapter.setBasePath("/admin/queues");
|
||||||
|
return serverAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerCronJobs() {
|
||||||
|
return cronJobs.map((registerCronJob) => registerCronJob());
|
||||||
|
}
|
109
server/sentry-remix.ts
Normal file
109
server/sentry-remix.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import type { Request, Response } from "express";
|
||||||
|
import type { ActionFunction, DataFunctionArgs, LoaderFunction, ServerBuild } from "@remix-run/node";
|
||||||
|
import { isResponse } from "@remix-run/server-runtime/responses";
|
||||||
|
import type { Transaction } from "@sentry/types";
|
||||||
|
import * as Sentry from "@sentry/node";
|
||||||
|
import { v4 as uuid } from "uuid";
|
||||||
|
|
||||||
|
import { __getSession } from "~/utils/session.server";
|
||||||
|
import type { SessionData } from "~/utils/auth.server";
|
||||||
|
|
||||||
|
function wrapDataFunc(func: ActionFunction | LoaderFunction, routeId: string, method: string) {
|
||||||
|
const ogFunc = func;
|
||||||
|
|
||||||
|
return async (args: DataFunctionArgs) => {
|
||||||
|
const session = await __getSession(args.request.headers.get("Cookie"));
|
||||||
|
const sessionData: SessionData | undefined = session.data.user;
|
||||||
|
if (sessionData) {
|
||||||
|
Sentry.setUser({
|
||||||
|
id: sessionData.user.id,
|
||||||
|
email: sessionData.user.email,
|
||||||
|
role: sessionData.user.role,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Sentry.configureScope((scope) => scope.setUser(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentTransaction: Transaction | undefined = args.context && args.context.__sentry_transaction;
|
||||||
|
const transaction = parentTransaction?.startChild({
|
||||||
|
op: `${method}:${routeId}`,
|
||||||
|
description: `${method}: ${routeId}`,
|
||||||
|
});
|
||||||
|
if (transaction) {
|
||||||
|
transaction.setStatus("ok");
|
||||||
|
transaction.transaction = parentTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await ogFunc(args);
|
||||||
|
} catch (error) {
|
||||||
|
if (isResponse(error)) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sentry.captureException(error, {
|
||||||
|
tags: {
|
||||||
|
global_id: parentTransaction && parentTransaction.tags["global_id"],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
transaction?.setStatus("internal_error");
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
transaction?.finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register Sentry across your entire remix build.
|
||||||
|
export function registerSentry(build: ServerBuild) {
|
||||||
|
type Route = ServerBuild["routes"][string];
|
||||||
|
|
||||||
|
const routes: Record<string, Route> = {};
|
||||||
|
|
||||||
|
for (const [id, route] of Object.entries(build.routes)) {
|
||||||
|
const newRoute: Route = { ...route, module: { ...route.module } };
|
||||||
|
|
||||||
|
if (route.module.action) {
|
||||||
|
newRoute.module.action = wrapDataFunc(route.module.action, id, "action");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route.module.loader) {
|
||||||
|
newRoute.module.loader = wrapDataFunc(route.module.loader, id, "loader");
|
||||||
|
}
|
||||||
|
|
||||||
|
routes[id] = newRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...build,
|
||||||
|
routes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sentryLoadContext(req: Request, res: Response) {
|
||||||
|
const transaction = Sentry.getCurrentHub().startTransaction({
|
||||||
|
op: "request",
|
||||||
|
name: `${req.method}: ${req.url}`,
|
||||||
|
description: `${req.method}: ${req.url}`,
|
||||||
|
metadata: {
|
||||||
|
requestPath: req.url,
|
||||||
|
},
|
||||||
|
tags: {
|
||||||
|
global_id: uuid(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
transaction && transaction.setStatus("internal_error");
|
||||||
|
|
||||||
|
res.once("finish", () => {
|
||||||
|
if (transaction) {
|
||||||
|
transaction.setHttpStatus(res.statusCode);
|
||||||
|
transaction.setTag("http.status_code", res.statusCode);
|
||||||
|
transaction.setTag("http.method", req.method);
|
||||||
|
transaction.finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
__sentry_transaction: transaction,
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user