mirror of
https://github.com/diced/zipline.git
synced 2026-04-28 10:43:06 -07:00
fix: packages update + various perf fixes
This commit is contained in:
@@ -101,7 +101,7 @@ export default defineConfig(
|
|||||||
},
|
},
|
||||||
|
|
||||||
settings: {
|
settings: {
|
||||||
react: { version: 'detect' },
|
react: { version: '19' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
60
package.json
60
package.json
@@ -5,12 +5,12 @@
|
|||||||
"version": "4.5.2",
|
"version": "4.5.2",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsx scripts/build.ts",
|
"build": "tsx scripts/build.ts",
|
||||||
"dev": "cross-env NODE_ENV=development DEBUG=zipline tsx --require dotenv/config --enable-source-maps ./src/server",
|
"dev": "cross-env NODE_ENV=development DEBUG=zipline tsx --require ./src/dotenv.js --enable-source-maps ./src/server",
|
||||||
"dev:nd": "cross-env NODE_ENV=development tsx --require dotenv/config --enable-source-maps ./src/server",
|
"dev:nd": "cross-env NODE_ENV=development tsx --require ./src/dotenv.js --enable-source-maps ./src/server",
|
||||||
"dev:inspector": "cross-env NODE_ENV=development DEBUG=zipline tsx --require dotenv/config --inspect=0.0.0.0:9229 --enable-source-maps ./src/server",
|
"dev:inspector": "cross-env NODE_ENV=development DEBUG=zipline tsx --require ./src/dotenv.js --inspect=0.0.0.0:9229 --enable-source-maps ./src/server",
|
||||||
"start": "cross-env NODE_ENV=production node --trace-warnings --require dotenv/config ./build/server",
|
"start": "cross-env NODE_ENV=production node --trace-warnings --require ./src/dotenv.js ./build/server",
|
||||||
"start:inspector": "cross-env NODE_ENV=production node --require dotenv/config --inspect=0.0.0.0:9229 --enable-source-maps ./build/server",
|
"start:inspector": "cross-env NODE_ENV=production node --require ./src/dotenv.js --inspect=0.0.0.0:9229 --enable-source-maps ./build/server",
|
||||||
"ctl": "NODE_ENV=production node --require dotenv/config --enable-source-maps ./build/ctl",
|
"ctl": "NODE_ENV=production node --require ./src/dotenv.js --enable-source-maps ./build/ctl",
|
||||||
"validate": "tsx scripts/validate.ts",
|
"validate": "tsx scripts/validate.ts",
|
||||||
"openapi": "tsx scripts/openapi.ts",
|
"openapi": "tsx scripts/openapi.ts",
|
||||||
"db:prototype": "prisma db push --skip-generate && prisma generate --no-hints",
|
"db:prototype": "prisma db push --skip-generate && prisma generate --no-hints",
|
||||||
@@ -22,8 +22,8 @@
|
|||||||
"docker:compose:dev:logs": "docker compose --file docker-compose.dev.yml logs -f"
|
"docker:compose:dev:logs": "docker compose --file docker-compose.dev.yml logs -f"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "3.726.1",
|
"@aws-sdk/client-s3": "3.1025.0",
|
||||||
"@aws-sdk/lib-storage": "3.726.1",
|
"@aws-sdk/lib-storage": "3.1025.0",
|
||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.3.1",
|
||||||
"@dnd-kit/sortable": "^10.0.0",
|
"@dnd-kit/sortable": "^10.0.0",
|
||||||
"@dnd-kit/utilities": "^3.2.2",
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
@@ -34,15 +34,15 @@
|
|||||||
"@fastify/sensible": "^6.0.4",
|
"@fastify/sensible": "^6.0.4",
|
||||||
"@fastify/static": "^9.0.0",
|
"@fastify/static": "^9.0.0",
|
||||||
"@fastify/swagger": "^9.7.0",
|
"@fastify/swagger": "^9.7.0",
|
||||||
"@mantine/charts": "^8.3.18",
|
"@mantine/charts": "^9.0.1",
|
||||||
"@mantine/code-highlight": "^8.3.18",
|
"@mantine/code-highlight": "^9.0.1",
|
||||||
"@mantine/core": "^8.3.18",
|
"@mantine/core": "^9.0.1",
|
||||||
"@mantine/dates": "^8.3.18",
|
"@mantine/dates": "^9.0.1",
|
||||||
"@mantine/dropzone": "^8.3.18",
|
"@mantine/dropzone": "^9.0.1",
|
||||||
"@mantine/form": "^8.3.18",
|
"@mantine/form": "^9.0.1",
|
||||||
"@mantine/hooks": "^8.3.18",
|
"@mantine/hooks": "^9.0.1",
|
||||||
"@mantine/modals": "^8.3.18",
|
"@mantine/modals": "^9.0.1",
|
||||||
"@mantine/notifications": "^8.3.18",
|
"@mantine/notifications": "^9.0.1",
|
||||||
"@prisma/adapter-pg": "6.13.0",
|
"@prisma/adapter-pg": "6.13.0",
|
||||||
"@prisma/client": "6.13.0",
|
"@prisma/client": "6.13.0",
|
||||||
"@prisma/engines": "6.13.0",
|
"@prisma/engines": "6.13.0",
|
||||||
@@ -50,8 +50,8 @@
|
|||||||
"@prisma/migrate": "6.13.0",
|
"@prisma/migrate": "6.13.0",
|
||||||
"@simplewebauthn/browser": "^13.3.0",
|
"@simplewebauthn/browser": "^13.3.0",
|
||||||
"@simplewebauthn/server": "^13.3.0",
|
"@simplewebauthn/server": "^13.3.0",
|
||||||
"@smithy/node-http-handler": "^4.1.1",
|
"@smithy/node-http-handler": "^4.5.2",
|
||||||
"@tabler/icons-react": "^3.40.0",
|
"@tabler/icons-react": "^3.41.1",
|
||||||
"archiver": "^7.0.1",
|
"archiver": "^7.0.1",
|
||||||
"argon2": "^0.44.0",
|
"argon2": "^0.44.0",
|
||||||
"asciinema-player": "^3.15.1",
|
"asciinema-player": "^3.15.1",
|
||||||
@@ -63,8 +63,7 @@
|
|||||||
"cross-env": "^10.1.0",
|
"cross-env": "^10.1.0",
|
||||||
"dayjs": "^1.11.20",
|
"dayjs": "^1.11.20",
|
||||||
"detect-browser": "^5.3.0",
|
"detect-browser": "^5.3.0",
|
||||||
"devalue": "^5.6.4",
|
"devalue": "^5.7.0",
|
||||||
"dotenv": "^17.3.1",
|
|
||||||
"fast-glob": "^3.3.3",
|
"fast-glob": "^3.3.3",
|
||||||
"fastify": "^5.8.4",
|
"fastify": "^5.8.4",
|
||||||
"fastify-plugin": "^5.1.0",
|
"fastify-plugin": "^5.1.0",
|
||||||
@@ -74,7 +73,7 @@
|
|||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"iron-session": "^8.0.4",
|
"iron-session": "^8.0.4",
|
||||||
"isomorphic-dompurify": "^3.7.1",
|
"isomorphic-dompurify": "^3.7.1",
|
||||||
"katex": "^0.16.42",
|
"katex": "^0.16.45",
|
||||||
"mantine-datatable": "^8.3.13",
|
"mantine-datatable": "^8.3.13",
|
||||||
"ms": "^2.1.3",
|
"ms": "^2.1.3",
|
||||||
"multer": "2.1.1",
|
"multer": "2.1.1",
|
||||||
@@ -84,13 +83,12 @@
|
|||||||
"react": "^19.2.4",
|
"react": "^19.2.4",
|
||||||
"react-dom": "^19.2.4",
|
"react-dom": "^19.2.4",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"react-router-dom": "^7.13.2",
|
"react-router-dom": "^7.14.0",
|
||||||
"react-window": "1.8.11",
|
"react-virtuoso": "^4.18.4",
|
||||||
"remark-gfm": "^4.0.1",
|
"remark-gfm": "^4.0.1",
|
||||||
"sharp": "^0.34.5",
|
"sharp": "^0.34.5",
|
||||||
"swr": "^2.4.1",
|
"swr": "^2.4.1",
|
||||||
"typescript-eslint": "^8.57.2",
|
"vite": "^8.0.5",
|
||||||
"vite": "^8.0.2",
|
|
||||||
"zod": "^4.3.6",
|
"zod": "^4.3.6",
|
||||||
"zustand": "^5.0.12"
|
"zustand": "^5.0.12"
|
||||||
},
|
},
|
||||||
@@ -102,19 +100,18 @@
|
|||||||
"@types/katex": "^0.16.8",
|
"@types/katex": "^0.16.8",
|
||||||
"@types/ms": "^2.1.0",
|
"@types/ms": "^2.1.0",
|
||||||
"@types/multer": "^2.1.0",
|
"@types/multer": "^2.1.0",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.12.2",
|
||||||
"@types/qrcode": "^1.5.6",
|
"@types/qrcode": "^1.5.6",
|
||||||
"@types/react": "^19.2.14",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@types/react-window": "^1.8.8",
|
|
||||||
"@vitejs/plugin-react": "^6.0.1",
|
"@vitejs/plugin-react": "^6.0.1",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^10.2.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||||
"eslint-plugin-prettier": "^5.5.4",
|
"eslint-plugin-prettier": "^5.5.4",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
"eslint-plugin-react-refresh": "^0.4.24",
|
"eslint-plugin-react-refresh": "^0.5.2",
|
||||||
"eslint-plugin-unused-imports": "^4.3.0",
|
"eslint-plugin-unused-imports": "^4.3.0",
|
||||||
"postcss": "^8.5.8",
|
"postcss": "^8.5.8",
|
||||||
"postcss-preset-mantine": "^1.18.0",
|
"postcss-preset-mantine": "^1.18.0",
|
||||||
@@ -124,7 +121,8 @@
|
|||||||
"tsc-alias": "^1.8.16",
|
"tsc-alias": "^1.8.16",
|
||||||
"tsup": "^8.5.1",
|
"tsup": "^8.5.1",
|
||||||
"tsx": "^4.21.0",
|
"tsx": "^4.21.0",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^6.0.2",
|
||||||
|
"typescript-eslint": "^8.58.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
|
|||||||
2763
pnpm-lock.yaml
generated
2763
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,7 @@ export default function ReloadPage() {
|
|||||||
Why am I seeing this?
|
Why am I seeing this?
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Collapse in={view}>
|
<Collapse expanded={view}>
|
||||||
<GenericError
|
<GenericError
|
||||||
title='Failed to fetch dynamically imported module'
|
title='Failed to fetch dynamically imported module'
|
||||||
message='This error can occur when a new version of the app is deployed while you have the page open. Please reload the page to update to the latest version.'
|
message='This error can occur when a new version of the app is deployed while you have the page open. Please reload the page to update to the latest version.'
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ export default function ViewFileId() {
|
|||||||
</Group>
|
</Group>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
<Collapse in={detailsOpen}>
|
<Collapse expanded={detailsOpen}>
|
||||||
<Paper m='md' p='md' withBorder>
|
<Paper m='md' p='md' withBorder>
|
||||||
{user?.view!.content && (
|
{user?.view!.content && (
|
||||||
<Typography>
|
<Typography>
|
||||||
|
|||||||
@@ -396,7 +396,7 @@ export default function FileTable({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Collapse in={selectedFiles.length > 0}>
|
<Collapse expanded={selectedFiles.length > 0}>
|
||||||
<Paper withBorder p='sm' my='sm'>
|
<Paper withBorder p='sm' my='sm'>
|
||||||
<Text size='sm' c='dimmed' mb='xs'>
|
<Text size='sm' c='dimmed' mb='xs'>
|
||||||
Selections are saved across page changes
|
Selections are saved across page changes
|
||||||
@@ -487,7 +487,7 @@ export default function FileTable({
|
|||||||
</Collapse>
|
</Collapse>
|
||||||
|
|
||||||
{modals && setModals && modals.idSearch && (
|
{modals && setModals && modals.idSearch && (
|
||||||
<Collapse in={modals.idSearch}>
|
<Collapse expanded={modals.idSearch}>
|
||||||
<Paper withBorder p='sm' mt='sm'>
|
<Paper withBorder p='sm' mt='sm'>
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder='Search by ID'
|
placeholder='Search by ID'
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ export default function DashboardFolders() {
|
|||||||
{filesOpen ? '▼' : '▶'} {currentFolder.name}'s files{' '}
|
{filesOpen ? '▼' : '▶'} {currentFolder.name}'s files{' '}
|
||||||
{currentFolder._count ? `(${currentFolder._count.files})` : ''}
|
{currentFolder._count ? `(${currentFolder._count.files})` : ''}
|
||||||
</Text>
|
</Text>
|
||||||
<Collapse in={filesOpen}>
|
<Collapse expanded={filesOpen}>
|
||||||
{view === 'grid' ? (
|
{view === 'grid' ? (
|
||||||
<Paper withBorder p='sm'>
|
<Paper withBorder p='sm'>
|
||||||
<FilesGridView folderId={currentFolderId} />
|
<FilesGridView folderId={currentFolderId} />
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ export default function Export3Details({ export3 }: { export3: Export3 }) {
|
|||||||
{envOpened ? 'Hide' : 'Show'} OS Details
|
{envOpened ? 'Hide' : 'Show'} OS Details
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Collapse in={osOpened}>
|
<Collapse expanded={osOpened}>
|
||||||
<HighlightCode language='json' code={JSON.stringify(export3.request.os, null, 2)} />
|
<HighlightCode language='json' code={JSON.stringify(export3.request.os, null, 2)} />
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|
||||||
@@ -147,7 +147,7 @@ export default function Export3Details({ export3 }: { export3: Export3 }) {
|
|||||||
{envOpened ? 'Hide' : 'Show'} Environment
|
{envOpened ? 'Hide' : 'Show'} Environment
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Collapse in={envOpened}>
|
<Collapse expanded={envOpened}>
|
||||||
<Paper withBorder>
|
<Paper withBorder>
|
||||||
<Table>
|
<Table>
|
||||||
<Table.Thead>
|
<Table.Thead>
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ export default function Export3Details({ export4 }: { export4: Export4 }) {
|
|||||||
{envOpened ? 'Hide' : 'Show'} OS Details
|
{envOpened ? 'Hide' : 'Show'} OS Details
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Collapse in={osOpened}>
|
<Collapse expanded={osOpened}>
|
||||||
<Paper withBorder>
|
<Paper withBorder>
|
||||||
<Table>
|
<Table>
|
||||||
<Table.Thead>
|
<Table.Thead>
|
||||||
@@ -217,7 +217,7 @@ export default function Export3Details({ export4 }: { export4: Export4 }) {
|
|||||||
{envOpened ? 'Hide' : 'Show'} Environment
|
{envOpened ? 'Hide' : 'Show'} Environment
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Collapse in={envOpened}>
|
<Collapse expanded={envOpened}>
|
||||||
<Paper withBorder>
|
<Paper withBorder>
|
||||||
<Table>
|
<Table>
|
||||||
<Table.Thead>
|
<Table.Thead>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default function Export4ImportSettings({
|
|||||||
{showSettings ? 'Hide' : 'Show'} Settings to be Imported
|
{showSettings ? 'Hide' : 'Show'} Settings to be Imported
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Collapse in={showSettings}>
|
<Collapse expanded={showSettings}>
|
||||||
<Paper withBorder>
|
<Paper withBorder>
|
||||||
<Table>
|
<Table>
|
||||||
<Table.Thead>
|
<Table.Thead>
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ export default function DashboardServerSettings() {
|
|||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
{(data?.tampered?.length ?? 0) > 0 && (
|
{(data?.tampered?.length ?? 0) > 0 && (
|
||||||
<Collapse in={opened} transitionDuration={180}>
|
<Collapse expanded={opened} transitionDuration={180}>
|
||||||
<Alert
|
<Alert
|
||||||
color='red'
|
color='red'
|
||||||
title='Environment Variable Settings'
|
title='Environment Variable Settings'
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ export default function Discord({
|
|||||||
{...formOnUpload.getInputProps('discordOnUploadEmbed', { type: 'checkbox' })}
|
{...formOnUpload.getInputProps('discordOnUploadEmbed', { type: 'checkbox' })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Collapse in={formOnUpload.values.discordOnUploadEmbed}>
|
<Collapse expanded={formOnUpload.values.discordOnUploadEmbed}>
|
||||||
<Paper withBorder p='sm' mt='md'>
|
<Paper withBorder p='sm' mt='md'>
|
||||||
<SimpleGrid cols={{ base: 1, md: 2 }} spacing='lg'>
|
<SimpleGrid cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||||
<TextInput
|
<TextInput
|
||||||
@@ -348,7 +348,7 @@ export default function Discord({
|
|||||||
{...formOnShorten.getInputProps('discordOnShortenEmbed', { type: 'checkbox' })}
|
{...formOnShorten.getInputProps('discordOnShortenEmbed', { type: 'checkbox' })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Collapse in={formOnShorten.values.discordOnShortenEmbed}>
|
<Collapse expanded={formOnShorten.values.discordOnShortenEmbed}>
|
||||||
<Paper withBorder p='sm' mt='md'>
|
<Paper withBorder p='sm' mt='md'>
|
||||||
<SimpleGrid cols={{ base: 1, md: 2 }} spacing='lg'>
|
<SimpleGrid cols={{ base: 1, md: 2 }} spacing='lg'>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export default function SettingsDashboard() {
|
|||||||
label='Default Domain'
|
label='Default Domain'
|
||||||
description='Set the default domain used for copied links anywhere in the dashboard. Leave blank or select "Default domain" to use the current domain that serves the dashboard.'
|
description='Set the default domain used for copied links anywhere in the dashboard. Leave blank or select "Default domain" to use the current domain that serves the dashboard.'
|
||||||
value={settings.domain}
|
value={settings.domain}
|
||||||
onChange={(value) => update('domain', value ?? '')}
|
onChange={(value) => update('domain', (value as string) ?? '')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ export default function UploadFile({ title, folder }: { title?: string; folder?:
|
|||||||
</Group>
|
</Group>
|
||||||
</Dropzone>
|
</Dropzone>
|
||||||
|
|
||||||
<Collapse in={progress.percent > 0 && progress.percent < 100}>
|
<Collapse expanded={progress.percent > 0 && progress.percent < 100}>
|
||||||
{progress.percent > 0 && progress.percent < 100 && (
|
{progress.percent > 0 && progress.percent < 100 && (
|
||||||
<Progress.Root my='sm' size='xl'>
|
<Progress.Root my='sm' size='xl'>
|
||||||
<Progress.Section value={progress.percent} animated>
|
<Progress.Section value={progress.percent} animated>
|
||||||
@@ -204,7 +204,7 @@ export default function UploadFile({ title, folder }: { title?: string; folder?:
|
|||||||
)}
|
)}
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|
||||||
<Collapse in={progress.speed > 0 && progress.remaining > 0}>
|
<Collapse expanded={progress.speed > 0 && progress.remaining > 0}>
|
||||||
<Paper withBorder p='xs' radius='sm'>
|
<Paper withBorder p='xs' radius='sm'>
|
||||||
<Text ta='center' size='sm'>
|
<Text ta='center' size='sm'>
|
||||||
{bytes(progress.speed)}/s, {humanizeDuration(progress.remaining)} remaining
|
{bytes(progress.speed)}/s, {humanizeDuration(progress.remaining)} remaining
|
||||||
@@ -212,7 +212,7 @@ export default function UploadFile({ title, folder }: { title?: string; folder?:
|
|||||||
</Paper>
|
</Paper>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|
||||||
<Collapse in={progress.percent === 100}>
|
<Collapse expanded={progress.percent === 100}>
|
||||||
<Paper withBorder p='xs' radius='sm'>
|
<Paper withBorder p='xs' radius='sm'>
|
||||||
<Text ta='center' size='sm' c='yellow' fw={500}>
|
<Text ta='center' size='sm' c='yellow' fw={500}>
|
||||||
Finalizing upload(s)...
|
Finalizing upload(s)...
|
||||||
|
|||||||
@@ -380,7 +380,7 @@ export default function UploadOptionsButton({ folder, numFiles }: { folder?: str
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
value={options.overrides_returnDomain ?? ''}
|
value={options.overrides_returnDomain ?? ''}
|
||||||
onChange={(value) => setOption('overrides_returnDomain', value || null)}
|
onChange={(value) => setOption('overrides_returnDomain', (value as string) || null)}
|
||||||
comboboxProps={{
|
comboboxProps={{
|
||||||
withinPortal: true,
|
withinPortal: true,
|
||||||
portalProps: {
|
portalProps: {
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { ActionIcon, Button, CopyButton, Paper, ScrollArea, Text, useMantineTheme } from '@mantine/core';
|
import { ActionIcon, Button, CopyButton, Paper, Text, useMantineTheme } from '@mantine/core';
|
||||||
import { IconCheck, IconChevronDown, IconChevronUp, IconClipboardCopy } from '@tabler/icons-react';
|
import { IconCheck, IconChevronDown, IconChevronUp, IconClipboardCopy } from '@tabler/icons-react';
|
||||||
import type { HLJSApi } from 'highlight.js';
|
import type { HLJSApi } from 'highlight.js';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { FixedSizeList as List } from 'react-window';
|
import { Virtuoso } from 'react-virtuoso';
|
||||||
|
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import './HighlightCode.theme.scss';
|
|
||||||
import * as sanitize from 'isomorphic-dompurify';
|
import * as sanitize from 'isomorphic-dompurify';
|
||||||
|
import './HighlightCode.theme.scss';
|
||||||
|
|
||||||
export default function HighlightCode({ language, code }: { language: string; code: string }) {
|
export default function HighlightCode({ language, code }: { language: string; code: string }) {
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
@@ -20,37 +19,33 @@ export default function HighlightCode({ language, code }: { language: string; co
|
|||||||
import('highlight.js').then((mod) => setHljs(mod.default || mod));
|
import('highlight.js').then((mod) => setHljs(mod.default || mod));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const lines = useMemo(() => code.split('\n'), [code]);
|
const cleanedCode = sanitize.sanitize(code, { USE_PROFILES: { html: true } });
|
||||||
const visible = expanded || noClamp ? lines.length : Math.min(lines.length, 50);
|
const lines = cleanedCode.split('\n');
|
||||||
const expandable = !noClamp && lines.length > 50;
|
const isExpandable = !noClamp && lines.length > 50;
|
||||||
|
|
||||||
|
const totalCount = isExpandable && !expanded ? 50 : lines.length;
|
||||||
|
const estimatedHeight = Math.min(totalCount * 24, 400);
|
||||||
|
|
||||||
const lang = useMemo(() => {
|
const lang = useMemo(() => {
|
||||||
if (!hljs) return 'plaintext';
|
if (!hljs) return 'plaintext';
|
||||||
if (hljs.getLanguage(language)) return language;
|
return hljs.getLanguage(language) ? language : 'plaintext';
|
||||||
|
|
||||||
return 'plaintext';
|
|
||||||
}, [hljs, language]);
|
}, [hljs, language]);
|
||||||
|
|
||||||
const hlLines = useMemo(() => {
|
const hlLines = useMemo(() => {
|
||||||
if (!hljs) return lines;
|
if (!hljs) return lines;
|
||||||
|
return lines.map((line) => hljs.highlight(line || ' ', { language: lang }).value);
|
||||||
return lines.map(
|
|
||||||
(line) =>
|
|
||||||
hljs.highlight(line, {
|
|
||||||
language: lang,
|
|
||||||
}).value,
|
|
||||||
);
|
|
||||||
}, [lines, hljs, lang]);
|
}, [lines, hljs, lang]);
|
||||||
|
|
||||||
const Row = ({ index, style }: { index: number; style: React.CSSProperties }) => (
|
const rowRenderer = (index: number) => (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
...style,
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'flex-start',
|
alignItems: 'flex-start',
|
||||||
whiteSpace: 'pre',
|
whiteSpace: 'pre',
|
||||||
fontFamily: 'monospace',
|
fontFamily: theme.fontFamilyMonospace,
|
||||||
fontSize: '0.8rem',
|
fontSize: '0.8rem',
|
||||||
|
lineHeight: '1.5',
|
||||||
|
backgroundColor: 'transparent',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
@@ -69,16 +64,14 @@ export default function HighlightCode({ language, code }: { language: string; co
|
|||||||
|
|
||||||
<code
|
<code
|
||||||
className='theme hljs'
|
className='theme hljs'
|
||||||
style={{ flex: 1, fontSize: '0.8rem' }}
|
style={{ flex: 1, padding: 0, background: 'none', alignSelf: 'center' }}
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{ __html: hlLines[index] }}
|
||||||
__html: sanitize.sanitize(hlLines[index], { USE_PROFILES: { html: true } }),
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper withBorder p='xs' my='md' pos='relative'>
|
<Paper withBorder p='xs' my='md' pos='relative' style={{ overflow: 'hidden' }}>
|
||||||
<CopyButton value={code}>
|
<CopyButton value={code}>
|
||||||
{({ copied, copy }) => (
|
{({ copied, copy }) => (
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
@@ -86,40 +79,39 @@ export default function HighlightCode({ language, code }: { language: string; co
|
|||||||
variant='outline'
|
variant='outline'
|
||||||
color={copied ? 'green' : 'gray'}
|
color={copied ? 'green' : 'gray'}
|
||||||
size='md'
|
size='md'
|
||||||
style={{ zIndex: 4, position: 'absolute', top: '0.5rem', right: '0.5rem' }}
|
style={{ zIndex: 10, position: 'absolute', top: '0.5rem', right: '0.5rem' }}
|
||||||
>
|
>
|
||||||
{!copied ? (
|
{copied ? (
|
||||||
<IconClipboardCopy size='1rem' />
|
|
||||||
) : (
|
|
||||||
<IconCheck color={theme.colors.green[4]} size='1rem' />
|
<IconCheck color={theme.colors.green[4]} size='1rem' />
|
||||||
|
) : (
|
||||||
|
<IconClipboardCopy size='1rem' />
|
||||||
)}
|
)}
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
)}
|
)}
|
||||||
</CopyButton>
|
</CopyButton>
|
||||||
|
|
||||||
{noClamp ? (
|
<div style={{ height: noClamp && (expanded || !isExpandable) ? 'auto' : estimatedHeight }}>
|
||||||
<ScrollArea type='auto' offsetScrollbars={false}>
|
<Virtuoso
|
||||||
<div>
|
style={{ height: '100%' }}
|
||||||
{hlLines.map((_, index) => (
|
totalCount={totalCount}
|
||||||
<Row key={index} index={index} style={{}} />
|
itemContent={rowRenderer}
|
||||||
))}
|
initialItemCount={30}
|
||||||
|
increaseViewportBy={200}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ScrollArea>
|
|
||||||
) : (
|
|
||||||
<ScrollArea type='auto' offsetScrollbars={false} style={{ maxHeight: 400 }}>
|
|
||||||
<List height={400} width='100%' itemCount={visible} itemSize={20} overscanCount={10}>
|
|
||||||
{Row}
|
|
||||||
</List>
|
|
||||||
</ScrollArea>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{expandable && (
|
{isExpandable && (
|
||||||
<Button
|
<Button
|
||||||
variant='light'
|
variant='light'
|
||||||
size='compact-sm'
|
size='compact-sm'
|
||||||
onClick={() => setExpanded((e) => !e)}
|
onClick={() => setExpanded((e) => !e)}
|
||||||
leftSection={expanded ? <IconChevronUp size='1rem' /> : <IconChevronDown size='1rem' />}
|
leftSection={expanded ? <IconChevronUp size='1rem' /> : <IconChevronDown size='1rem' />}
|
||||||
style={{ position: 'absolute', bottom: '0.5rem', right: '0.5rem' }}
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: '0.5rem',
|
||||||
|
right: '0.5rem',
|
||||||
|
zIndex: 10,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{expanded ? 'Show Less' : `Show More (${lines.length - 50} more lines)`}
|
{expanded ? 'Show Less' : `Show More (${lines.length - 50} more lines)`}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
5
src/dotenv.js
Normal file
5
src/dotenv.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// --require ./src/dotenv.js
|
||||||
|
// loads environment variables from a .env file into process.env on startup
|
||||||
|
try {
|
||||||
|
process.loadEnvFile('.env');
|
||||||
|
} catch {}
|
||||||
@@ -63,6 +63,8 @@ export class S3Datasource extends Datasource {
|
|||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
requestChecksumCalculation: 'WHEN_REQUIRED',
|
||||||
|
responseChecksumValidation: 'WHEN_REQUIRED',
|
||||||
});
|
});
|
||||||
|
|
||||||
this.ensureReadWriteAccess();
|
this.ensureReadWriteAccess();
|
||||||
|
|||||||
@@ -4,10 +4,14 @@ const MAX = 256 - (256 % CHARSET_LENGTH);
|
|||||||
|
|
||||||
function getRandomValues(array: Uint8Array) {
|
function getRandomValues(array: Uint8Array) {
|
||||||
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
|
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
|
||||||
return crypto.getRandomValues(array);
|
// TODO: remove any cast when the types are fixed...
|
||||||
|
return crypto.getRandomValues(<any>array);
|
||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
console.error(
|
||||||
return require('crypto').webcrypto.getRandomValues(array);
|
'No secure random number generator available. Please use node@22+ and a supported platform.',
|
||||||
|
);
|
||||||
|
|
||||||
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user