Update MixFetch docs playground + components (#6479)
This commit is contained in:
@@ -1,86 +1,273 @@
|
||||
```tsx copy filename="mixFetchExample.tsx"
|
||||
import React, { useState } from "react";
|
||||
```tsx
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
import CircularProgress from "@mui/material/CircularProgress";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Box from "@mui/material/Box";
|
||||
import { mixFetch } from "@nymproject/mix-fetch-full-fat";
|
||||
import { mixFetch, createMixFetch } from "@nymproject/mix-fetch-full-fat";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import type { SetupMixFetchOps } from "@nymproject/mix-fetch-full-fat";
|
||||
|
||||
const defaultUrl = "https://nymtech.net/.wellknown/network-requester/exit-policy.txt";
|
||||
const defaultUrl =
|
||||
"https://nymtech.net/.wellknown/network-requester/exit-policy.txt";
|
||||
const args = { mode: "unsafe-ignore-cors" };
|
||||
|
||||
const mixFetchOptions: SetupMixFetchOps = {
|
||||
preferredGateway: "2xU4CBE6QiiYt6EyBXSALwxkNvM7gqJfjHXaMkjiFmYW", // with WSS
|
||||
// preferredNetworkRequester:
|
||||
// "CTDxrcXgrZHWyCWnuCgjpJPghQUcEVz1HkhUr5mGdFnT.3UAww1YWNyVNYNWFQL1LaHYouQtDiXBGK5GiDZgpXkTK@2RFtU5BwxvJJXagAWAEuaPgb5ZVPRoy2542TT93Edw6v",
|
||||
clientId: "docs-mixfetch-demo", // explicit ID
|
||||
preferredGateway: "q2A2cbooyC16YJzvdYaSMH9X3cSiieZNtfBr8cE8Fi1",
|
||||
mixFetchOverride: {
|
||||
requestTimeoutMs: 60_000,
|
||||
},
|
||||
forceTls: true, // force WSS
|
||||
};
|
||||
|
||||
// Log entry type for the visible log panel
|
||||
type LogLevel = "info" | "error" | "send" | "receive";
|
||||
type LogEntry = { timestamp: string; message: string; level: LogLevel };
|
||||
|
||||
const logColors: Record<LogLevel, string> = {
|
||||
info: "gray",
|
||||
error: "red",
|
||||
send: "blue",
|
||||
receive: "green",
|
||||
};
|
||||
|
||||
const logLabels: Record<LogLevel, string> = {
|
||||
info: "INFO",
|
||||
error: "ERROR",
|
||||
send: "SEND",
|
||||
receive: "RECV",
|
||||
};
|
||||
|
||||
export const MixFetch = () => {
|
||||
// MixFetch initialization state
|
||||
const [status, setStatus] = useState<"idle" | "starting" | "ready" | "error">("idle");
|
||||
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
||||
|
||||
// Log panel state
|
||||
const [logs, setLogs] = useState<LogEntry[]>([]);
|
||||
const logEndRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Single fetch state
|
||||
const [url, setUrl] = useState<string>(defaultUrl);
|
||||
const [html, setHtml] = useState<string>();
|
||||
const [busy, setBusy] = useState<boolean>(false);
|
||||
|
||||
// Concurrent fetch state
|
||||
const [concurrentResults, setConcurrentResults] = useState<string[]>([]);
|
||||
const [concurrentBusy, setConcurrentBusy] = useState<boolean>(false);
|
||||
|
||||
// Auto-scroll log panel to bottom
|
||||
useEffect(() => {
|
||||
logEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||
}, [logs]);
|
||||
|
||||
// Helper to add a timestamped log entry
|
||||
const addLog = (message: string, level: LogLevel) => {
|
||||
const timestamp = new Date().toISOString().substring(11, 23);
|
||||
setLogs((prev) => [...prev, { timestamp, message, level }]);
|
||||
};
|
||||
|
||||
// Initialize MixFetch explicitly via createMixFetch
|
||||
const handleStart = async () => {
|
||||
try {
|
||||
setStatus("starting");
|
||||
setErrorMsg(null);
|
||||
addLog("Starting MixFetch...", "info");
|
||||
await createMixFetch(mixFetchOptions);
|
||||
setStatus("ready");
|
||||
addLog("MixFetch is ready!", "info");
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
setStatus("error");
|
||||
setErrorMsg(msg);
|
||||
addLog(`Error: ${msg}`, "error");
|
||||
}
|
||||
};
|
||||
|
||||
// Single URL fetch — reuses the existing MixFetch singleton
|
||||
const handleFetch = async () => {
|
||||
try {
|
||||
setBusy(true);
|
||||
setHtml(undefined);
|
||||
addLog(`Sending request to ${url}...`, "send");
|
||||
const response = await mixFetch(url, args, mixFetchOptions);
|
||||
console.log(response);
|
||||
const resHtml = await response.text();
|
||||
setHtml(resHtml);
|
||||
addLog(`Response received (${resHtml.length} bytes)`, "receive");
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
addLog(`Fetch error: ${msg}`, "error");
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Send 5 concurrent requests to different URLs on the same domain
|
||||
const handleConcurrentFetch = async () => {
|
||||
const baseUrl = "https://jsonplaceholder.typicode.com/posts/";
|
||||
const count = 5;
|
||||
try {
|
||||
setConcurrentBusy(true);
|
||||
setConcurrentResults([]);
|
||||
addLog(
|
||||
`Starting ${count} concurrent requests to ${baseUrl}1-${count}...`,
|
||||
"send",
|
||||
);
|
||||
// Fire off all requests concurrently using Promise.all
|
||||
const requests = Array.from({ length: count }, (_, i) => {
|
||||
const targetUrl = `${baseUrl}${i + 1}`;
|
||||
return mixFetch(targetUrl, args, mixFetchOptions)
|
||||
.then((res) => res.json())
|
||||
.then((json: { id: number; title: string }) => {
|
||||
const entry = `[${json.id}] ${json.title}`;
|
||||
addLog(entry, "receive");
|
||||
return entry;
|
||||
});
|
||||
});
|
||||
const results = await Promise.all(requests);
|
||||
setConcurrentResults(results);
|
||||
addLog(`All ${count} concurrent requests completed!`, "info");
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
addLog(`Concurrent fetch error: ${msg}`, "error");
|
||||
} finally {
|
||||
setConcurrentBusy(false);
|
||||
}
|
||||
};
|
||||
|
||||
const isReady = status === "ready";
|
||||
|
||||
const statusText = {
|
||||
idle: "Not started",
|
||||
starting: "Starting...",
|
||||
ready: "Ready",
|
||||
error: `Error: ${errorMsg}`,
|
||||
};
|
||||
const statusColor = {
|
||||
idle: "gray",
|
||||
starting: "orange",
|
||||
ready: "green",
|
||||
error: "red",
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ marginTop: "1rem" }}>
|
||||
<Stack direction="row">
|
||||
<TextField
|
||||
disabled={busy}
|
||||
fullWidth
|
||||
label="URL"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
defaultValue={defaultUrl}
|
||||
onChange={(e) => setUrl(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
variant="outlined"
|
||||
disabled={busy}
|
||||
sx={{ marginLeft: "1rem" }}
|
||||
onClick={handleFetch}
|
||||
>
|
||||
Fetch
|
||||
</Button>
|
||||
</Stack>
|
||||
{/* Start MixFetch */}
|
||||
<Paper sx={{ p: 2, mb: 2 }} variant="outlined">
|
||||
<Stack direction="row" alignItems="center" spacing={2}>
|
||||
<Button
|
||||
variant="contained"
|
||||
disabled={status === "starting" || status === "ready"}
|
||||
onClick={handleStart}
|
||||
>
|
||||
Start MixFetch
|
||||
</Button>
|
||||
{status === "starting" && <CircularProgress size={20} />}
|
||||
<Typography
|
||||
fontFamily="monospace"
|
||||
fontSize="small"
|
||||
sx={{ color: statusColor[status] }}
|
||||
>
|
||||
{statusText[status]}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
{busy && (
|
||||
<Box mt={4}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
)}
|
||||
{html && (
|
||||
<>
|
||||
<Box mt={4}>
|
||||
<strong>Response</strong>
|
||||
{/* Fetch controls — disabled until MixFetch is ready */}
|
||||
<Box
|
||||
sx={{
|
||||
opacity: isReady ? 1 : 0.5,
|
||||
pointerEvents: isReady ? "auto" : "none",
|
||||
}}
|
||||
>
|
||||
{/* Single fetch */}
|
||||
<Stack direction="row">
|
||||
<TextField
|
||||
disabled={busy}
|
||||
fullWidth
|
||||
label="URL"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
defaultValue={defaultUrl}
|
||||
onChange={(e) => setUrl(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
variant="outlined"
|
||||
disabled={busy}
|
||||
sx={{ marginLeft: "1rem" }}
|
||||
onClick={handleFetch}
|
||||
>
|
||||
Fetch
|
||||
</Button>
|
||||
</Stack>
|
||||
{busy && (
|
||||
<Box mt={2}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
<Paper sx={{ p: 2, mt: 1 }} elevation={4}>
|
||||
<Typography fontFamily="monospace" fontSize="small">
|
||||
{html}
|
||||
</Typography>
|
||||
)}
|
||||
{html && (
|
||||
<>
|
||||
<Box mt={2}>
|
||||
<strong>Response</strong>
|
||||
</Box>
|
||||
<Paper sx={{ p: 2, mt: 1 }} elevation={4}>
|
||||
<Typography fontFamily="monospace" fontSize="small">
|
||||
{html}
|
||||
</Typography>
|
||||
</Paper>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Concurrent fetch */}
|
||||
<Box mt={3}>
|
||||
<strong>Concurrent Requests</strong>
|
||||
<Box mt={1}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
disabled={concurrentBusy}
|
||||
onClick={handleConcurrentFetch}
|
||||
>
|
||||
Send 5 Concurrent Requests (posts/1-5)
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
{concurrentBusy && (
|
||||
<Box mt={2}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
)}
|
||||
{concurrentResults.length > 0 && (
|
||||
<Paper sx={{ p: 2, mt: 2 }} elevation={4}>
|
||||
{concurrentResults.map((result, i) => (
|
||||
<Typography key={i} fontFamily="monospace" fontSize="small">
|
||||
{result}
|
||||
</Typography>
|
||||
))}
|
||||
</Paper>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{/* Log Panel */}
|
||||
{logs.length > 0 && (
|
||||
<Paper
|
||||
sx={{ p: 2, mt: 3, maxHeight: 200, overflow: "auto" }}
|
||||
variant="outlined"
|
||||
>
|
||||
<strong>Log</strong>
|
||||
{logs.map((entry, i) => (
|
||||
<Typography
|
||||
key={i}
|
||||
fontFamily="monospace"
|
||||
fontSize="small"
|
||||
sx={{ color: logColors[entry.level] }}
|
||||
>
|
||||
{entry.timestamp} [{logLabels[entry.level]}] {entry.message}
|
||||
</Typography>
|
||||
))}
|
||||
<div ref={logEndRef} />
|
||||
</Paper>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
import CircularProgress from "@mui/material/CircularProgress";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Box from "@mui/material/Box";
|
||||
import { mixFetch } from "@nymproject/mix-fetch-full-fat";
|
||||
import { mixFetch, createMixFetch } from "@nymproject/mix-fetch-full-fat";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import type { SetupMixFetchOps } from "@nymproject/mix-fetch-full-fat";
|
||||
@@ -12,8 +12,8 @@ import type { SetupMixFetchOps } from "@nymproject/mix-fetch-full-fat";
|
||||
const defaultUrl =
|
||||
"https://nymtech.net/.wellknown/network-requester/exit-policy.txt";
|
||||
const args = { mode: "unsafe-ignore-cors" };
|
||||
|
||||
const mixFetchOptions: SetupMixFetchOps = {
|
||||
clientId: "docs-mixfetch-demo", // explicit ID
|
||||
preferredGateway: "q2A2cbooyC16YJzvdYaSMH9X3cSiieZNtfBr8cE8Fi1",
|
||||
mixFetchOverride: {
|
||||
requestTimeoutMs: 60_000,
|
||||
@@ -21,64 +21,260 @@ const mixFetchOptions: SetupMixFetchOps = {
|
||||
forceTls: true, // force WSS
|
||||
};
|
||||
|
||||
// Log entry type for the visible log panel
|
||||
type LogLevel = "info" | "error" | "send" | "receive";
|
||||
type LogEntry = { timestamp: string; message: string; level: LogLevel };
|
||||
|
||||
// Color map for log levels
|
||||
const logColors: Record<LogLevel, string> = {
|
||||
info: "gray",
|
||||
error: "red",
|
||||
send: "blue",
|
||||
receive: "green",
|
||||
};
|
||||
|
||||
// Label map for log levels
|
||||
const logLabels: Record<LogLevel, string> = {
|
||||
info: "INFO",
|
||||
error: "ERROR",
|
||||
send: "SEND",
|
||||
receive: "RECV",
|
||||
};
|
||||
|
||||
export const MixFetch = () => {
|
||||
// MixFetch initialization state
|
||||
const [status, setStatus] = useState<"idle" | "starting" | "ready" | "error">(
|
||||
"idle"
|
||||
);
|
||||
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
||||
|
||||
// Log panel state
|
||||
const [logs, setLogs] = useState<LogEntry[]>([]);
|
||||
|
||||
// Single fetch state
|
||||
const [url, setUrl] = useState<string>(defaultUrl);
|
||||
const [html, setHtml] = useState<string>();
|
||||
const [busy, setBusy] = useState<boolean>(false);
|
||||
|
||||
// Concurrent fetch state
|
||||
const [concurrentResults, setConcurrentResults] = useState<string[]>([]);
|
||||
const [concurrentBusy, setConcurrentBusy] = useState<boolean>(false);
|
||||
|
||||
// Auto-scroll within the log panel when new entries are added (without scrolling the page)
|
||||
const logContainerRef = useRef<HTMLDivElement>(null);
|
||||
useEffect(() => {
|
||||
if (logContainerRef.current) {
|
||||
logContainerRef.current.scrollTop = logContainerRef.current.scrollHeight;
|
||||
}
|
||||
}, [logs]);
|
||||
|
||||
// Helper to add a timestamped log entry
|
||||
const addLog = (message: string, level: LogLevel) => {
|
||||
const timestamp = new Date().toISOString().substring(11, 23); // HH:MM:SS.mmm
|
||||
setLogs((prev) => [...prev, { timestamp, message, level }]);
|
||||
};
|
||||
|
||||
// Initialize MixFetch explicitly via createMixFetch
|
||||
const handleStart = async () => {
|
||||
try {
|
||||
setStatus("starting");
|
||||
setErrorMsg(null);
|
||||
addLog("Starting MixFetch...", "info");
|
||||
await createMixFetch(mixFetchOptions);
|
||||
setStatus("ready");
|
||||
addLog("MixFetch is ready!", "info");
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
setStatus("error");
|
||||
setErrorMsg(msg);
|
||||
addLog(`Error: ${msg}`, "error");
|
||||
}
|
||||
};
|
||||
|
||||
// Single URL fetch — mixFetch reuses the existing singleton
|
||||
const handleFetch = async () => {
|
||||
try {
|
||||
setBusy(true);
|
||||
setHtml(undefined);
|
||||
addLog(`Sending request to ${url}...`, "send");
|
||||
const response = await mixFetch(url, args, mixFetchOptions);
|
||||
console.log(response);
|
||||
const resHtml = await response.text();
|
||||
setHtml(resHtml);
|
||||
addLog(`Response received (${resHtml.length} bytes)`, "receive");
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
addLog(`Fetch error: ${msg}`, "error");
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Send 5 concurrent requests to different URLs on the same domain
|
||||
const handleConcurrentFetch = async () => {
|
||||
const baseUrl = "https://jsonplaceholder.typicode.com/posts/";
|
||||
const count = 5;
|
||||
try {
|
||||
setConcurrentBusy(true);
|
||||
setConcurrentResults([]);
|
||||
addLog(
|
||||
`Starting ${count} concurrent requests to ${baseUrl}1-${count}...`,
|
||||
"send"
|
||||
);
|
||||
// Fire off all requests concurrently using Promise.all
|
||||
const requests = Array.from({ length: count }, (_, i) => {
|
||||
const targetUrl = `${baseUrl}${i + 1}`;
|
||||
return mixFetch(targetUrl, args, mixFetchOptions)
|
||||
.then((res) => res.json())
|
||||
.then((json: { id: number; title: string }) => {
|
||||
const entry = `[${json.id}] ${json.title}`;
|
||||
addLog(entry, "receive");
|
||||
return entry;
|
||||
});
|
||||
});
|
||||
const results = await Promise.all(requests);
|
||||
setConcurrentResults(results);
|
||||
addLog(`All ${count} concurrent requests completed!`, "info");
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
addLog(`Concurrent fetch error: ${msg}`, "error");
|
||||
} finally {
|
||||
setConcurrentBusy(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Are fetch controls enabled?
|
||||
const isReady = status === "ready";
|
||||
|
||||
// Status text + color for the startup indicator
|
||||
const statusText: Record<typeof status, string> = {
|
||||
idle: "Not started",
|
||||
starting: "Starting...",
|
||||
ready: "Ready",
|
||||
error: `Error: ${errorMsg}`,
|
||||
};
|
||||
const statusColor: Record<typeof status, string> = {
|
||||
idle: "gray",
|
||||
starting: "orange",
|
||||
ready: "green",
|
||||
error: "red",
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ marginTop: "1rem" }}>
|
||||
<Stack direction="row">
|
||||
<TextField
|
||||
disabled={busy}
|
||||
fullWidth
|
||||
label="URL"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
defaultValue={defaultUrl}
|
||||
onChange={(e) => setUrl(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
variant="outlined"
|
||||
disabled={busy}
|
||||
sx={{ marginLeft: "1rem" }}
|
||||
onClick={handleFetch}
|
||||
>
|
||||
Fetch
|
||||
</Button>
|
||||
</Stack>
|
||||
{/* --- Start MixFetch Section --- */}
|
||||
<Paper sx={{ p: 2, mb: 2 }} variant="outlined">
|
||||
<Stack direction="row" alignItems="center" spacing={2}>
|
||||
<Button
|
||||
variant="contained"
|
||||
disabled={status === "starting" || status === "ready"}
|
||||
onClick={handleStart}
|
||||
>
|
||||
Start MixFetch
|
||||
</Button>
|
||||
{status === "starting" && <CircularProgress size={20} />}
|
||||
<Typography
|
||||
fontFamily="monospace"
|
||||
fontSize="small"
|
||||
sx={{ color: statusColor[status] }}
|
||||
>
|
||||
{statusText[status]}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
{busy && (
|
||||
<Box mt={4}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
)}
|
||||
{html && (
|
||||
<>
|
||||
<Box mt={4}>
|
||||
<strong>Response</strong>
|
||||
{/* --- Fetch Controls (disabled until ready) --- */}
|
||||
<Box
|
||||
sx={{
|
||||
opacity: isReady ? 1 : 0.5,
|
||||
pointerEvents: isReady ? "auto" : "none",
|
||||
}}
|
||||
>
|
||||
{/* Single fetch */}
|
||||
<Stack direction="row">
|
||||
<TextField
|
||||
disabled={busy}
|
||||
fullWidth
|
||||
label="URL"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
defaultValue={defaultUrl}
|
||||
onChange={(e) => setUrl(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
variant="outlined"
|
||||
disabled={busy}
|
||||
sx={{ marginLeft: "1rem" }}
|
||||
onClick={handleFetch}
|
||||
>
|
||||
Fetch
|
||||
</Button>
|
||||
</Stack>
|
||||
{busy && (
|
||||
<Box mt={2}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
<Paper sx={{ p: 2, mt: 1 }} elevation={4}>
|
||||
<Typography fontFamily="monospace" fontSize="small">
|
||||
{html}
|
||||
</Typography>
|
||||
)}
|
||||
{html && (
|
||||
<>
|
||||
<Box mt={2}>
|
||||
<strong>Response</strong>
|
||||
</Box>
|
||||
<Paper sx={{ p: 2, mt: 1 }} elevation={4}>
|
||||
<Typography fontFamily="monospace" fontSize="small">
|
||||
{html}
|
||||
</Typography>
|
||||
</Paper>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Concurrent fetch demo */}
|
||||
<Box mt={3}>
|
||||
<strong>Concurrent Requests</strong>
|
||||
<Box mt={1}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
disabled={concurrentBusy}
|
||||
onClick={handleConcurrentFetch}
|
||||
>
|
||||
Send 5 Concurrent Requests (posts/1-5)
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
{concurrentBusy && (
|
||||
<Box mt={2}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
)}
|
||||
{concurrentResults.length > 0 && (
|
||||
<Paper sx={{ p: 2, mt: 2 }} elevation={4}>
|
||||
{concurrentResults.map((result, i) => (
|
||||
<Typography key={i} fontFamily="monospace" fontSize="small">
|
||||
{result}
|
||||
</Typography>
|
||||
))}
|
||||
</Paper>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{/* --- Log Panel --- */}
|
||||
{logs.length > 0 && (
|
||||
<Paper
|
||||
ref={logContainerRef}
|
||||
sx={{ p: 2, mt: 3, maxHeight: 200, overflow: "auto" }}
|
||||
variant="outlined"
|
||||
>
|
||||
<strong>Log</strong>
|
||||
{logs.map((entry, i) => (
|
||||
<Typography
|
||||
key={i}
|
||||
fontFamily="monospace"
|
||||
fontSize="small"
|
||||
sx={{ color: logColors[entry.level] }}
|
||||
>
|
||||
{entry.timestamp} [{logLabels[entry.level]}] {entry.message}
|
||||
</Typography>
|
||||
))}
|
||||
</Paper>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1 +1 @@
|
||||
Friday, February 20th 2026, 13:42:15 UTC
|
||||
Monday, February 23rd 2026, 22:45:55 UTC
|
||||
|
||||
@@ -11,7 +11,7 @@ options:
|
||||
--no_routing_history Display node stats without routing history
|
||||
--no_verloc_metrics Display node stats without verloc metrics
|
||||
-m, --markdown Display results in markdown format
|
||||
-o [OUTPUT], --output [OUTPUT]
|
||||
-o, --output [OUTPUT]
|
||||
Save results to file (in current dir or supply with
|
||||
path without filename)
|
||||
```
|
||||
|
||||
@@ -12,8 +12,7 @@ usage: nym-node-cli install [-h] [-V] [-d BRANCH] [-v]
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
-V, --version show program's version number and exit
|
||||
-d BRANCH, --dev BRANCH
|
||||
Define github branch (default: develop)
|
||||
-d, --dev BRANCH Define github branch (default: develop)
|
||||
-v, --verbose Show full error tracebacks
|
||||
--mode {mixnode,entry-gateway,exit-gateway}
|
||||
Node mode: 'mixnode', 'entry-gateway', or 'exit-
|
||||
|
||||
@@ -62,6 +62,8 @@ Options:
|
||||
Tunnel port announced to external clients wishing to connect to the wireguard interface. Useful in the instances where the node is behind a proxy [env: NYMNODE_WG_ANNOUNCED_PORT=]
|
||||
--wireguard-private-network-prefix <WIREGUARD_PRIVATE_NETWORK_PREFIX>
|
||||
The prefix denoting the maximum number of the clients that can be connected via Wireguard. The maximum value for IPv4 is 32 and for IPv6 is 128 [env: NYMNODE_WG_PRIVATE_NETWORK_PREFIX=]
|
||||
--wireguard-userspace <WIREGUARD_USERSPACE>
|
||||
Use userspace implementation of WireGuard (wireguard-go) instead of kernel module. Useful in containerized environments without kernel WireGuard support [env: NYMNODE_WG_USERSPACE=] [possible values: true, false]
|
||||
--verloc-bind-address <VERLOC_BIND_ADDRESS>
|
||||
Socket address this node will use for binding its verloc API. default: `[::]:1790` [env: NYMNODE_VERLOC_BIND_ADDRESS=]
|
||||
--verloc-announce-port <VERLOC_ANNOUNCE_PORT>
|
||||
@@ -80,6 +82,8 @@ Options:
|
||||
Endpoint to query to retrieve current upgrade mode attestation. This argument should never be set outside testnets and local networks [env: NYMNODE_UPGRADE_MODE_ATTESTATION_URL=]
|
||||
--upgrade-mode-attester-public-key <UPGRADE_MODE_ATTESTER_PUBLIC_KEY>
|
||||
Expected public key of the entity signing the published attestation. This argument should never be set outside testnets and local networks [env: NYMNODE_UPGRADE_MODE_ATTESTER_PUBKEY=]
|
||||
--lp-use-mock-ecash <LP_USE_MOCK_ECASH>
|
||||
Use mock ecash manager for LP testing. WARNING: Only use this for local testing! Never enable in production. When enabled, the LP listener will accept any credential without blockchain verification [env: NYMNODE_LP_USE_MOCK_ECASH=] [possible values: true, false]
|
||||
--upstream-exit-policy-url <UPSTREAM_EXIT_POLICY_URL>
|
||||
Specifies the url for an upstream source of the exit policy used by this node [env: NYMNODE_UPSTREAM_EXIT_POLICY=]
|
||||
--open-proxy <OPEN_PROXY>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
"@nextui-org/accordion": "^2.0.40",
|
||||
"@nextui-org/react": "^2.4.8",
|
||||
"@nymproject/contract-clients": ">=1.2.4-rc.2 || ^1",
|
||||
"@nymproject/mix-fetch-full-fat": ">=1.5.1-rc.0 || ^1.4.1",
|
||||
"@nymproject/mix-fetch-full-fat": "^1.4.2",
|
||||
"@nymproject/sdk-full-fat": ">=1.5.1-rc.0 || ^1.4.1",
|
||||
"@redocly/cli": "^1.25.15",
|
||||
"@types/mdx": "^2.0.13",
|
||||
|
||||
@@ -13,7 +13,7 @@ Sounds great, are there any catches? Well, there are a few (for now):
|
||||
|
||||
- For now, `mixfetch` doesn't work with SURBS, although this will change in the future.
|
||||
|
||||
- For now, `mixFetch` cannot deal with concurrent requests with the same base URL.
|
||||
- `mixFetch` supports concurrent requests (up to 10) to either different URLs on the same domain or different domains. Duplicate requests to the exact same URL will be deduplicated.
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
Right now Gateways are not required to run a Secure Websocket (WSS) listener, so only a subset of nodes running in Gateway mode have configured their nodes to do so.
|
||||
@@ -33,6 +33,7 @@ curl -X 'GET' \
|
||||
import type { SetupMixFetchOps } from '@nymproject/mix-fetch';
|
||||
|
||||
const mixFetchOptions: SetupMixFetchOps = {
|
||||
clientId: "my-mixfetch-client", // explicit ID to avoid stale default IndexedDB storage
|
||||
preferredGateway: "q2A2cbooyC16YJzvdYaSMH9X3cSiieZNtfBr8cE8Fi1", // with WSS
|
||||
mixFetchOverride: {
|
||||
requestTimeoutMs: 60_000,
|
||||
@@ -78,7 +79,7 @@ import { mixFetch } from '@nymproject/mix-fetch-full-fat';
|
||||
|
||||
##### Example: using the `mixFetch` client:
|
||||
|
||||
`Get` and `Post` outputs will be observable from your console.
|
||||
`Get`, `Post`, and `Concurrent` outputs will be observable from your console. MixFetch auto-initializes on the first request. Individual concurrent results are logged as they arrive.
|
||||
|
||||
```ts
|
||||
import './App.css';
|
||||
@@ -86,6 +87,7 @@ import { mixFetch, SetupMixFetchOps } from '@nymproject/mix-fetch-full-fat';
|
||||
import React from 'react';
|
||||
|
||||
const mixFetchOptions: SetupMixFetchOps = {
|
||||
clientId: "my-mixfetch-client", // explicit ID to avoid stale default IndexedDB storage
|
||||
preferredGateway: '23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb', // with WSS
|
||||
preferredNetworkRequester:
|
||||
'HuNL1pFprNSKW6jdqppibXP5KNKCNJxDh7ivpYcoULN9.C62NahRTUf6kqpNtDVHXoVriQr6yyaU5LtxdgpbsGrtA@23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb',
|
||||
@@ -103,7 +105,7 @@ export function HttpGET() {
|
||||
const response = await mixFetch('https://nym.com/favicon.svg', { mode: 'unsafe-ignore-cors' }, mixFetchOptions);
|
||||
const text = await response.text();
|
||||
console.log('response was', text);
|
||||
setHtml(html);
|
||||
setHtml(text);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -146,11 +148,63 @@ export function HttpPOST() {
|
||||
);
|
||||
}
|
||||
|
||||
// Send 5 concurrent requests to different URLs on the same domain using Promise.all
|
||||
export function HttpConcurrent() {
|
||||
const [results, setResults] = React.useState<string[]>([]);
|
||||
const [busy, setBusy] = React.useState(false);
|
||||
|
||||
async function fetchConcurrent() {
|
||||
const baseUrl = 'https://jsonplaceholder.typicode.com/posts/';
|
||||
const count = 5;
|
||||
setBusy(true);
|
||||
setResults([]);
|
||||
console.log(`Starting ${count} concurrent requests to ${baseUrl}1-${count}...`);
|
||||
|
||||
try {
|
||||
// Fire off all requests at once with Promise.all
|
||||
const requests = Array.from({ length: count }, (_, i) => {
|
||||
const url = `${baseUrl}${i + 1}`;
|
||||
return mixFetch(url, { mode: 'unsafe-ignore-cors' }, mixFetchOptions)
|
||||
.then((res) => res.json())
|
||||
.then((json: { id: number; title: string }) => {
|
||||
const entry = `[${json.id}] ${json.title}`;
|
||||
console.log(entry);
|
||||
return entry;
|
||||
});
|
||||
});
|
||||
|
||||
const allResults = await Promise.all(requests);
|
||||
setResults(allResults);
|
||||
console.log('All concurrent requests completed!', allResults);
|
||||
} catch (err) {
|
||||
console.error('Concurrent fetch error:', err);
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button onClick={fetchConcurrent} disabled={busy}>
|
||||
{busy ? 'Fetching...' : 'Send 5 Concurrent Requests'}
|
||||
</button>
|
||||
{results.length > 0 && (
|
||||
<ul>
|
||||
{results.map((r, i) => (
|
||||
<li key={i}>{r}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<>
|
||||
<HttpGET />
|
||||
<HttpPOST />
|
||||
<HttpConcurrent />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Generated
+50
-38
@@ -78,14 +78,14 @@ importers:
|
||||
specifier: '>=1.2.4-rc.2 || ^1'
|
||||
version: 1.4.1
|
||||
'@nymproject/mix-fetch-full-fat':
|
||||
specifier: '>=1.5.1-rc.0 || ^1.4.1'
|
||||
version: 1.4.1
|
||||
specifier: ^1.4.2
|
||||
version: 1.4.2
|
||||
'@nymproject/sdk-full-fat':
|
||||
specifier: '>=1.5.1-rc.0 || ^1.4.1'
|
||||
version: 1.4.1
|
||||
'@redocly/cli':
|
||||
specifier: ^1.25.15
|
||||
version: 1.34.5(ajv@8.17.1)
|
||||
version: 1.34.5(ajv@6.12.6)
|
||||
'@types/mdx':
|
||||
specifier: ^2.0.13
|
||||
version: 2.0.13
|
||||
@@ -1062,7 +1062,6 @@ packages:
|
||||
'@next/swc-linux-x64-gnu@15.5.0':
|
||||
resolution: {integrity: sha512-zPisT+obYypM/l6EZ0yRkK3LEuoZqHaSoYKj+5jiD9ESHwdr6QhnabnNxYkdy34uCigNlWIaCbjFmQ8FY5AlxA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@next/swc-linux-x64-gnu@15.5.7':
|
||||
@@ -1705,8 +1704,8 @@ packages:
|
||||
'@nymproject/contract-clients@1.4.1':
|
||||
resolution: {integrity: sha512-HuJZ4Hv+Rl6ZZEtCHKgurNLJapM+QQRJlGkevFH2a4UdqUqF9omUkUi3AVes4679dPoSFgvA7plyVSDBdbgV6w==}
|
||||
|
||||
'@nymproject/mix-fetch-full-fat@1.4.1':
|
||||
resolution: {integrity: sha512-AMa21sEd9FELqAJe1lCyHPqxxbc13ApiJ1P/exAslQjiFPb/de/3Ow0FHqKGNPrwyVRS/T2pSzjQ3l8TddiEBA==}
|
||||
'@nymproject/mix-fetch-full-fat@1.4.2':
|
||||
resolution: {integrity: sha512-QHPwa7A+c/2VUm4Imq2I21toFiZhbZxcjHud1sFsE9hN5BWxZ+QJKV2bg9oBUzulzoQabsk48RA13/hqU7c4KA==}
|
||||
|
||||
'@nymproject/sdk-full-fat@1.4.1':
|
||||
resolution: {integrity: sha512-dh5bvMUj3m8nEssvO8Nl66WpcJAjwRZrGNwqfczJWLG4nX3Vt95tPLv4v0/Z1W3DQWQFW6WmEPPYHNjl18V/fA==}
|
||||
@@ -3215,6 +3214,11 @@ packages:
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
acorn@8.16.0:
|
||||
resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
agent-base@7.1.4:
|
||||
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -3390,8 +3394,9 @@ packages:
|
||||
base64-js@1.5.1:
|
||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||
|
||||
baseline-browser-mapping@2.9.19:
|
||||
resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==}
|
||||
baseline-browser-mapping@2.10.0:
|
||||
resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
|
||||
bech32@1.1.4:
|
||||
@@ -3510,6 +3515,9 @@ packages:
|
||||
caniuse-lite@1.0.30001769:
|
||||
resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==}
|
||||
|
||||
caniuse-lite@1.0.30001774:
|
||||
resolution: {integrity: sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==}
|
||||
|
||||
cardinal@2.1.1:
|
||||
resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==}
|
||||
hasBin: true
|
||||
@@ -4022,8 +4030,8 @@ packages:
|
||||
duplexify@4.1.3:
|
||||
resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==}
|
||||
|
||||
electron-to-chromium@1.5.286:
|
||||
resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==}
|
||||
electron-to-chromium@1.5.302:
|
||||
resolution: {integrity: sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==}
|
||||
|
||||
elkjs@0.9.3:
|
||||
resolution: {integrity: sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==}
|
||||
@@ -5355,8 +5363,8 @@ packages:
|
||||
modern-ahocorasick@1.1.0:
|
||||
resolution: {integrity: sha512-sEKPVl2rM+MNVkGQt3ChdmD8YsigmXdn5NifZn6jiwn9LRJpWm8F3guhaqrJT/JOat6pwpbXEk6kv+b9DMIjsQ==}
|
||||
|
||||
motion-dom@12.34.0:
|
||||
resolution: {integrity: sha512-Lql3NuEcScRDxTAO6GgUsRHBZOWI/3fnMlkMcH5NftzcN37zJta+bpbMAV9px4Nj057TuvRooMK7QrzMCgtz6Q==}
|
||||
motion-dom@12.34.3:
|
||||
resolution: {integrity: sha512-sYgFe+pR9aIM7o4fhs2aXtOI+oqlUd33N9Yoxcgo1Fv7M20sRkHtCmzE/VRNIcq7uNJ+qio+Xubt1FXH3pQ+eQ==}
|
||||
|
||||
motion-utils@12.29.2:
|
||||
resolution: {integrity: sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A==}
|
||||
@@ -6709,8 +6717,8 @@ packages:
|
||||
webidl-conversions@3.0.1:
|
||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||
|
||||
webpack-sources@3.3.3:
|
||||
resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==}
|
||||
webpack-sources@3.3.4:
|
||||
resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
webpack@5.101.3:
|
||||
@@ -9307,7 +9315,7 @@ snapshots:
|
||||
|
||||
'@nymproject/contract-clients@1.4.1': {}
|
||||
|
||||
'@nymproject/mix-fetch-full-fat@1.4.1': {}
|
||||
'@nymproject/mix-fetch-full-fat@1.4.2': {}
|
||||
|
||||
'@nymproject/sdk-full-fat@1.4.1': {}
|
||||
|
||||
@@ -11046,7 +11054,7 @@ snapshots:
|
||||
require-from-string: 2.0.2
|
||||
uri-js-replace: 1.0.1
|
||||
|
||||
'@redocly/cli@1.34.5(ajv@8.17.1)':
|
||||
'@redocly/cli@1.34.5(ajv@6.12.6)':
|
||||
dependencies:
|
||||
'@opentelemetry/api': 1.9.0
|
||||
'@opentelemetry/exporter-trace-otlp-http': 0.53.0(@opentelemetry/api@1.9.0)
|
||||
@@ -11055,7 +11063,7 @@ snapshots:
|
||||
'@opentelemetry/semantic-conventions': 1.27.0
|
||||
'@redocly/config': 0.22.2
|
||||
'@redocly/openapi-core': 1.34.5
|
||||
'@redocly/respect-core': 1.34.5(ajv@8.17.1)
|
||||
'@redocly/respect-core': 1.34.5(ajv@6.12.6)
|
||||
abort-controller: 3.0.0
|
||||
chokidar: 3.6.0
|
||||
colorette: 1.4.0
|
||||
@@ -11098,12 +11106,12 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@redocly/respect-core@1.34.5(ajv@8.17.1)':
|
||||
'@redocly/respect-core@1.34.5(ajv@6.12.6)':
|
||||
dependencies:
|
||||
'@faker-js/faker': 7.6.0
|
||||
'@redocly/ajv': 8.11.2
|
||||
'@redocly/openapi-core': 1.34.5
|
||||
better-ajv-errors: 1.2.0(ajv@8.17.1)
|
||||
better-ajv-errors: 1.2.0(ajv@6.12.6)
|
||||
colorette: 2.0.20
|
||||
concat-stream: 2.0.0
|
||||
cookie: 0.7.2
|
||||
@@ -11810,9 +11818,9 @@ snapshots:
|
||||
dependencies:
|
||||
event-target-shim: 5.0.1
|
||||
|
||||
acorn-import-phases@1.0.4(acorn@8.15.0):
|
||||
acorn-import-phases@1.0.4(acorn@8.16.0):
|
||||
dependencies:
|
||||
acorn: 8.15.0
|
||||
acorn: 8.16.0
|
||||
|
||||
acorn-jsx@5.3.2(acorn@8.15.0):
|
||||
dependencies:
|
||||
@@ -11820,6 +11828,8 @@ snapshots:
|
||||
|
||||
acorn@8.15.0: {}
|
||||
|
||||
acorn@8.16.0: {}
|
||||
|
||||
agent-base@7.1.4: {}
|
||||
|
||||
ajv-draft-04@1.0.0(ajv@8.17.1):
|
||||
@@ -12009,15 +12019,15 @@ snapshots:
|
||||
|
||||
base64-js@1.5.1: {}
|
||||
|
||||
baseline-browser-mapping@2.9.19: {}
|
||||
baseline-browser-mapping@2.10.0: {}
|
||||
|
||||
bech32@1.1.4: {}
|
||||
|
||||
better-ajv-errors@1.2.0(ajv@8.17.1):
|
||||
better-ajv-errors@1.2.0(ajv@6.12.6):
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
'@humanwhocodes/momoa': 2.0.4
|
||||
ajv: 8.17.1
|
||||
ajv: 6.12.6
|
||||
chalk: 4.1.2
|
||||
jsonpointer: 5.0.1
|
||||
leven: 3.1.0
|
||||
@@ -12079,9 +12089,9 @@ snapshots:
|
||||
|
||||
browserslist@4.28.1:
|
||||
dependencies:
|
||||
baseline-browser-mapping: 2.9.19
|
||||
caniuse-lite: 1.0.30001769
|
||||
electron-to-chromium: 1.5.286
|
||||
baseline-browser-mapping: 2.10.0
|
||||
caniuse-lite: 1.0.30001774
|
||||
electron-to-chromium: 1.5.302
|
||||
node-releases: 2.0.27
|
||||
update-browserslist-db: 1.2.3(browserslist@4.28.1)
|
||||
|
||||
@@ -12135,6 +12145,8 @@ snapshots:
|
||||
|
||||
caniuse-lite@1.0.30001769: {}
|
||||
|
||||
caniuse-lite@1.0.30001774: {}
|
||||
|
||||
cardinal@2.1.1:
|
||||
dependencies:
|
||||
ansicolors: 0.3.2
|
||||
@@ -12672,7 +12684,7 @@ snapshots:
|
||||
readable-stream: 3.6.2
|
||||
stream-shift: 1.0.3
|
||||
|
||||
electron-to-chromium@1.5.286: {}
|
||||
electron-to-chromium@1.5.302: {}
|
||||
|
||||
elkjs@0.9.3: {}
|
||||
|
||||
@@ -12830,7 +12842,7 @@ snapshots:
|
||||
eslint: 8.46.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(eslint@8.46.0))(eslint@8.46.0)
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.46.0)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.46.0)
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.46.0)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(eslint@8.46.0))(eslint@8.46.0))(eslint@8.46.0)
|
||||
eslint-plugin-jsx-a11y: 6.10.2(eslint@8.46.0)
|
||||
eslint-plugin-react: 7.37.5(eslint@8.46.0)
|
||||
eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.46.0)
|
||||
@@ -12860,7 +12872,7 @@ snapshots:
|
||||
tinyglobby: 0.2.14
|
||||
unrs-resolver: 1.11.1
|
||||
optionalDependencies:
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.46.0)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.46.0)
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.46.0)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(eslint@8.46.0))(eslint@8.46.0))(eslint@8.46.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -12875,7 +12887,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.46.0)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.46.0):
|
||||
eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.46.0)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(eslint@8.46.0))(eslint@8.46.0))(eslint@8.46.0):
|
||||
dependencies:
|
||||
'@rtsao/scc': 1.1.0
|
||||
array-includes: 3.1.9
|
||||
@@ -13171,7 +13183,7 @@ snapshots:
|
||||
|
||||
framer-motion@12.23.12(@emotion/is-prop-valid@1.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
motion-dom: 12.34.0
|
||||
motion-dom: 12.34.3
|
||||
motion-utils: 12.29.2
|
||||
tslib: 2.8.1
|
||||
optionalDependencies:
|
||||
@@ -14491,7 +14503,7 @@ snapshots:
|
||||
|
||||
modern-ahocorasick@1.1.0: {}
|
||||
|
||||
motion-dom@12.34.0:
|
||||
motion-dom@12.34.3:
|
||||
dependencies:
|
||||
motion-utils: 12.29.2
|
||||
|
||||
@@ -15781,7 +15793,7 @@ snapshots:
|
||||
terser@5.46.0:
|
||||
dependencies:
|
||||
'@jridgewell/source-map': 0.3.11
|
||||
acorn: 8.15.0
|
||||
acorn: 8.16.0
|
||||
commander: 2.20.3
|
||||
source-map-support: 0.5.21
|
||||
|
||||
@@ -16171,7 +16183,7 @@ snapshots:
|
||||
|
||||
webidl-conversions@3.0.1: {}
|
||||
|
||||
webpack-sources@3.3.3: {}
|
||||
webpack-sources@3.3.4: {}
|
||||
|
||||
webpack@5.101.3:
|
||||
dependencies:
|
||||
@@ -16181,8 +16193,8 @@ snapshots:
|
||||
'@webassemblyjs/ast': 1.14.1
|
||||
'@webassemblyjs/wasm-edit': 1.14.1
|
||||
'@webassemblyjs/wasm-parser': 1.14.1
|
||||
acorn: 8.15.0
|
||||
acorn-import-phases: 1.0.4(acorn@8.15.0)
|
||||
acorn: 8.16.0
|
||||
acorn-import-phases: 1.0.4(acorn@8.16.0)
|
||||
browserslist: 4.28.1
|
||||
chrome-trace-event: 1.0.4
|
||||
enhanced-resolve: 5.19.0
|
||||
@@ -16199,7 +16211,7 @@ snapshots:
|
||||
tapable: 2.3.0
|
||||
terser-webpack-plugin: 5.3.16(webpack@5.101.3)
|
||||
watchpack: 2.5.1
|
||||
webpack-sources: 3.3.3
|
||||
webpack-sources: 3.3.4
|
||||
transitivePeerDependencies:
|
||||
- '@swc/core'
|
||||
- esbuild
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user