upd: web push
Deskripsi: - install package - table database - nb : masih blm bisa No Issues
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
"@tiptap/react": "^2.4.0",
|
||||
"@tiptap/starter-kit": "^2.4.0",
|
||||
"@types/lodash": "^4.17.6",
|
||||
"@types/web-push": "^3.6.3",
|
||||
"dayjs": "^1.11.11",
|
||||
"echarts": "^5.5.1",
|
||||
"echarts-for-react": "^3.0.2",
|
||||
@@ -52,6 +53,7 @@
|
||||
"readdirp": "^3.6.0",
|
||||
"recharts": "2",
|
||||
"rrule": "^2.8.1",
|
||||
"web-push": "^3.6.7",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -478,3 +478,8 @@ model ColorTheme {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model Subscription {
|
||||
id String @id @default(cuid())
|
||||
data Json
|
||||
}
|
||||
|
||||
BIN
public/icon-192x192.png
Normal file
BIN
public/icon-192x192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
77
public/wibu_worker.js
Normal file
77
public/wibu_worker.js
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(self.skipWaiting());
|
||||
console.log('Service worker installing...');
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
event.waitUntil(self.clients.claim());
|
||||
console.log('Service worker activating...');
|
||||
});
|
||||
|
||||
self.addEventListener('push', function (event) {
|
||||
console.log('Push event received:', event);
|
||||
|
||||
|
||||
let title = "Sistem Desa Mandiri";
|
||||
let options = {
|
||||
body: "Default notification body",
|
||||
icon: '/icon-192x192.png',
|
||||
badge: '/icon-192x192.png',
|
||||
image: '/icon-192x192.png',
|
||||
vibrate: [100, 50, 100],
|
||||
data: {
|
||||
dateOfArrival: Date.now(),
|
||||
primaryKey: '2',
|
||||
},
|
||||
};
|
||||
|
||||
if (event.data) {
|
||||
try {
|
||||
const data = event.data.json();
|
||||
title = data.title || title;
|
||||
options.body = data.body || options.body;
|
||||
options.icon = data.icon || options.icon;
|
||||
options.badge = data.badge || options.badge;
|
||||
options.image = data.image || options.image;
|
||||
options.data = {
|
||||
...options.data,
|
||||
...data.data, // Merging additional data from the event
|
||||
};
|
||||
|
||||
} catch (e) {
|
||||
console.error("Error parsing push event data:", e);
|
||||
}
|
||||
} else {
|
||||
console.warn("Push event has no data.");
|
||||
}
|
||||
|
||||
event.waitUntil(
|
||||
self.registration.showNotification(title, options)
|
||||
.then(() => console.log('Notification shown.', JSON.stringify(options, null, 2)))
|
||||
.catch(err => {
|
||||
console.error("Error showing notification:", err);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('notificationclick', function (event) {
|
||||
console.log('Notification click received.');
|
||||
|
||||
event.notification.close(); // Close the notification
|
||||
|
||||
event.waitUntil(
|
||||
clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {
|
||||
for (const client of clientList) {
|
||||
if (client.url.includes('http://localhost:3005') && 'focus' in client) {
|
||||
return client.focus();
|
||||
}
|
||||
}
|
||||
if (clients.openWindow) {
|
||||
return clients.openWindow('http://localhost:3005');
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error("Error handling notification click:", err);
|
||||
})
|
||||
);
|
||||
});
|
||||
17
src/app/(application)/web-push/page.tsx
Normal file
17
src/app/(application)/web-push/page.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { NotificationManager } from "@/module/_global/components/notification_manager";
|
||||
|
||||
const publicKey = process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY!;
|
||||
|
||||
console.log(
|
||||
process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY,
|
||||
process.env.VAPID_PRIVATE_KEY
|
||||
);
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<div>
|
||||
{/* <PushNotificationManager publicKey={publicKey} /> */}
|
||||
<NotificationManager publicKey={publicKey} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
6
src/app/api/get-subscribe/route.ts
Normal file
6
src/app/api/get-subscribe/route.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
|
||||
export async function GET() {
|
||||
const sub = await prisma.subscription.findMany();
|
||||
return new Response(JSON.stringify({ data: sub }));
|
||||
}
|
||||
70
src/app/api/send-notification/route.ts
Normal file
70
src/app/api/send-notification/route.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import webpush from "web-push";
|
||||
import prisma from "@/lib/prisma";
|
||||
|
||||
// Set VAPID details for web-push
|
||||
webpush.setVapidDetails(
|
||||
"mailto:bip.production.js@gmail.com",
|
||||
process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY!,
|
||||
process.env.VAPID_PRIVATE_KEY!
|
||||
);
|
||||
|
||||
export async function POST() {
|
||||
try {
|
||||
// Fetch all subscriptions from your database
|
||||
const subscriptions = await prisma.subscription.findMany();
|
||||
|
||||
if (!subscriptions || subscriptions.length === 0) {
|
||||
console.error("No subscriptions available to send notification");
|
||||
return new Response("No subscriptions available", { status: 400 });
|
||||
}
|
||||
|
||||
// Notification payload
|
||||
const notificationPayload = JSON.stringify({
|
||||
title: "Test Notification",
|
||||
body: "This is a test notification | makuro",
|
||||
icon: "/icon-192x192.png",
|
||||
badge: "/icon-192x192.png",
|
||||
image: "/icon-192x192.png",
|
||||
});
|
||||
|
||||
let successCount = 0;
|
||||
let failureCount = 0;
|
||||
|
||||
// Loop through all subscriptions and send notifications
|
||||
for (const sub of subscriptions) {
|
||||
try {
|
||||
const subscriptionData = sub.data as any;
|
||||
|
||||
await webpush.sendNotification(subscriptionData, notificationPayload);
|
||||
console.log(
|
||||
`Notification sent successfully to ${subscriptionData.endpoint}`
|
||||
);
|
||||
successCount++;
|
||||
} catch (error: any) {
|
||||
console.error(
|
||||
`Error sending push notification to subscription ${sub.id}:`,
|
||||
error
|
||||
);
|
||||
failureCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Return a success or failure response
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
message: `Notifications sent: ${successCount}, Failed: ${failureCount}`,
|
||||
success: failureCount === 0
|
||||
}),
|
||||
{ status: 200 }
|
||||
);
|
||||
} catch (error: any) {
|
||||
console.error("Error during notification process:", error);
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
error: error.message || "Failed to process notifications"
|
||||
}),
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
25
src/app/api/set-subscribe/route.ts
Normal file
25
src/app/api/set-subscribe/route.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import webpush from "web-push";
|
||||
import prisma from "@/lib/prisma";
|
||||
webpush.setVapidDetails(
|
||||
"mailto:bip.production.js@gmail.com",
|
||||
process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY!,
|
||||
process.env.VAPID_PRIVATE_KEY!
|
||||
);
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const { sub } = await req.json();
|
||||
console.log(sub);
|
||||
if (!sub || !sub.endpoint) {
|
||||
console.error("Invalid subscription object");
|
||||
return new Response("Invalid subscription object", { status: 400 });
|
||||
}
|
||||
|
||||
const data = await prisma.subscription.create({
|
||||
data: {
|
||||
id: sub.keys.auth,
|
||||
data: sub
|
||||
}
|
||||
});
|
||||
|
||||
return new Response(JSON.stringify({ data }));
|
||||
}
|
||||
11
src/app/api/unsubscribe/route.ts
Normal file
11
src/app/api/unsubscribe/route.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const { sub } = await req.json();
|
||||
const data = await prisma.subscription.delete({
|
||||
where: {
|
||||
id: sub.keys.auth
|
||||
}
|
||||
});
|
||||
return new Response(JSON.stringify({ data }));
|
||||
}
|
||||
29
src/app/manifest.ts
Normal file
29
src/app/manifest.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import type { MetadataRoute } from "next";
|
||||
|
||||
export default function manifest(): MetadataRoute.Manifest {
|
||||
return {
|
||||
name: "Sistem Desa Mandiri",
|
||||
short_name: "SDM",
|
||||
description: "Sistem Desa Mandiri",
|
||||
start_url: "/",
|
||||
display: "standalone",
|
||||
background_color: "#ffffff",
|
||||
theme_color: "#000000",
|
||||
icons: [
|
||||
{
|
||||
src: "/icon-192x192.png",
|
||||
sizes: "192x192",
|
||||
type: "image/png"
|
||||
},
|
||||
{
|
||||
src: "/icon-512x512.png",
|
||||
sizes: "512x512",
|
||||
type: "image/png"
|
||||
}
|
||||
],
|
||||
serviceworker: {
|
||||
src: "/wibu_worker.js"
|
||||
},
|
||||
|
||||
};
|
||||
}
|
||||
15
src/lib/prisma.ts
Normal file
15
src/lib/prisma.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
const prismaClientSingleton = () => {
|
||||
return new PrismaClient()
|
||||
}
|
||||
|
||||
declare const globalThis: {
|
||||
prismaGlobal: ReturnType<typeof prismaClientSingleton>;
|
||||
} & typeof global;
|
||||
|
||||
const prisma = globalThis.prismaGlobal ?? prismaClientSingleton()
|
||||
|
||||
export default prisma
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') globalThis.prismaGlobal = prisma
|
||||
13
src/lib/urlB64ToUint8Array.ts
Normal file
13
src/lib/urlB64ToUint8Array.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export const urlB64ToUint8Array = (base64String: string) => {
|
||||
const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
|
||||
const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
|
||||
|
||||
const rawData = window.atob(base64);
|
||||
const outputArray = new Uint8Array(rawData.length);
|
||||
|
||||
for (let i = 0; i < rawData.length; ++i) {
|
||||
outputArray[i] = rawData.charCodeAt(i);
|
||||
}
|
||||
return outputArray;
|
||||
};
|
||||
|
||||
46
src/lib/usePWAInstall.ts
Normal file
46
src/lib/usePWAInstall.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
export function usePWAInstall() {
|
||||
const [deferredPrompt, setDeferredPrompt] = useState<any>(null);
|
||||
const [isAppInstalled, setIsAppInstalled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const beforeInstallHandler = (e: any) => {
|
||||
e.preventDefault();
|
||||
setDeferredPrompt(e);
|
||||
};
|
||||
|
||||
|
||||
const appInstalledHandler = () => {
|
||||
setIsAppInstalled(true);
|
||||
};
|
||||
|
||||
window.addEventListener("beforeinstallprompt", beforeInstallHandler);
|
||||
window.addEventListener("appinstalled", appInstalledHandler);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("beforeinstallprompt", beforeInstallHandler);
|
||||
window.removeEventListener("appinstalled", appInstalledHandler);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleInstallClick = () => {
|
||||
if (deferredPrompt) {
|
||||
deferredPrompt.prompt();
|
||||
deferredPrompt.userChoice.then((choiceResult: any) => {
|
||||
if (choiceResult.outcome === "accepted") {
|
||||
console.log("User accepted the install prompt");
|
||||
} else {
|
||||
console.log("User dismissed the install prompt");
|
||||
}
|
||||
setDeferredPrompt(null);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
deferredPrompt,
|
||||
isAppInstalled,
|
||||
handleInstallClick,
|
||||
};
|
||||
}
|
||||
75
src/lib/usePushNotifications.ts
Normal file
75
src/lib/usePushNotifications.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { urlB64ToUint8Array } from "./urlB64ToUint8Array";
|
||||
|
||||
export function usePushNotifications(publicKey: string) {
|
||||
const [isSupported, setIsSupported] = useState(false);
|
||||
const [subscription, setSubscription] = useState<PushSubscription | null>(
|
||||
null
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if ("serviceWorker" in navigator && "PushManager" in window) {
|
||||
setIsSupported(true);
|
||||
registerServiceWorker();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const registerServiceWorker = async () => {
|
||||
try {
|
||||
const registration = await navigator.serviceWorker.register(
|
||||
"/wibu_worker.js",
|
||||
{
|
||||
scope: "/",
|
||||
updateViaCache: "none"
|
||||
}
|
||||
);
|
||||
const sub = await registration.pushManager.getSubscription();
|
||||
if (sub) {
|
||||
setSubscription(sub);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Service Worker registration failed:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const subscribeToPush = async () => {
|
||||
try {
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
const sub = await registration.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: urlB64ToUint8Array(publicKey)
|
||||
});
|
||||
|
||||
const res = await fetch("/api/set-subscribe", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ sub: sub.toJSON() })
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
setSubscription(sub);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Subscription error:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const unsubscribeFromPush = async () => {
|
||||
if (subscription) {
|
||||
await subscription.unsubscribe();
|
||||
setSubscription(null);
|
||||
await fetch("/api/unsubscribe", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ sub: subscription.toJSON() })
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
isSupported,
|
||||
subscription,
|
||||
subscribeToPush,
|
||||
unsubscribeFromPush
|
||||
};
|
||||
}
|
||||
83
src/module/_global/components/notification_manager.tsx
Normal file
83
src/module/_global/components/notification_manager.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
"use client";
|
||||
import { usePushNotifications } from "@/lib/usePushNotifications";
|
||||
import { usePWAInstall } from "@/lib/usePWAInstall";
|
||||
import { useState } from "react";
|
||||
|
||||
// test v1
|
||||
|
||||
export function NotificationManager({ publicKey }: { publicKey: string }) {
|
||||
const {
|
||||
isSupported,
|
||||
subscription,
|
||||
subscribeToPush,
|
||||
unsubscribeFromPush
|
||||
} = usePushNotifications(publicKey);
|
||||
const { deferredPrompt, isAppInstalled, handleInstallClick } =
|
||||
usePWAInstall();
|
||||
const [message, setMessage] = useState("halo apa kabar");
|
||||
|
||||
|
||||
const sendTestNotification = async () => {
|
||||
if (!subscription) return;
|
||||
|
||||
try {
|
||||
const res = await fetch("/api/send-notification", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ sub: subscription.toJSON(), message })
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
console.error("Failed to send notification:", res.statusText);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Notification error:", error);
|
||||
}
|
||||
};
|
||||
|
||||
if (!isSupported) {
|
||||
return <p>Push notifications are not supported in this browser.</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3>Push Notifications & PWA Install</h3>
|
||||
{subscription ? (
|
||||
<>
|
||||
<p>You are subscribed to push notifications.</p>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "10px"
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<button onClick={unsubscribeFromPush}>Unsubscribe</button>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter notification message"
|
||||
value={message}
|
||||
onChange={(e) => setMessage(e.target.value)}
|
||||
/>
|
||||
<div>
|
||||
<button onClick={sendTestNotification}>
|
||||
Send Test Notification
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p>You are not subscribed to push notifications.</p>
|
||||
<button onClick={subscribeToPush}>Subscribe</button>
|
||||
</>
|
||||
)}
|
||||
<hr />
|
||||
{!isAppInstalled && deferredPrompt && (
|
||||
<button onClick={handleInstallClick}>Install App</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
110
yarn.lock
110
yarn.lock
@@ -673,6 +673,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.6.tgz#193ced6a40c8006cfc1ca3f4553444fb38f0e543"
|
||||
integrity sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA==
|
||||
|
||||
"@types/node@*":
|
||||
version "22.5.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.5.tgz#52f939dd0f65fc552a4ad0b392f3c466cc5d7a44"
|
||||
integrity sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==
|
||||
dependencies:
|
||||
undici-types "~6.19.2"
|
||||
|
||||
"@types/node@^20.14.9":
|
||||
version "20.14.10"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.10.tgz#a1a218290f1b6428682e3af044785e5874db469a"
|
||||
@@ -700,6 +707,13 @@
|
||||
"@types/prop-types" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/web-push@^3.6.3":
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/web-push/-/web-push-3.6.3.tgz#7698cdeeabd70d1129a6e02bd58af1e985cdfa03"
|
||||
integrity sha512-v3oT4mMJsHeJ/rraliZ+7TbZtr5bQQuxcgD7C3/1q/zkAj29c8RE0F9lVZVu3hiQe5Z9fYcBreV7TLnfKR+4mg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@typescript-eslint/parser@^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0":
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.2.0.tgz#44356312aea8852a3a82deebdacd52ba614ec07a"
|
||||
@@ -780,6 +794,13 @@ agent-base@6:
|
||||
dependencies:
|
||||
debug "4"
|
||||
|
||||
agent-base@^7.0.2:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317"
|
||||
integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==
|
||||
dependencies:
|
||||
debug "^4.3.4"
|
||||
|
||||
ajv@^6.12.4:
|
||||
version "6.12.6"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
||||
@@ -964,6 +985,16 @@ arraybuffer.prototype.slice@^1.0.3:
|
||||
is-array-buffer "^3.0.4"
|
||||
is-shared-array-buffer "^1.0.2"
|
||||
|
||||
asn1.js@^5.3.0:
|
||||
version "5.4.1"
|
||||
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07"
|
||||
integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==
|
||||
dependencies:
|
||||
bn.js "^4.0.0"
|
||||
inherits "^2.0.1"
|
||||
minimalistic-assert "^1.0.0"
|
||||
safer-buffer "^2.1.0"
|
||||
|
||||
ast-types-flow@^0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6"
|
||||
@@ -998,6 +1029,11 @@ binary-extensions@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522"
|
||||
integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
|
||||
|
||||
bn.js@^4.0.0:
|
||||
version "4.12.0"
|
||||
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
|
||||
integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
@@ -1020,6 +1056,11 @@ braces@^3.0.3, braces@~3.0.2:
|
||||
dependencies:
|
||||
fill-range "^7.1.1"
|
||||
|
||||
buffer-equal-constant-time@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
|
||||
integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==
|
||||
|
||||
busboy@1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
|
||||
@@ -1422,6 +1463,13 @@ eastasianwidth@^0.2.0:
|
||||
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
|
||||
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
|
||||
|
||||
ecdsa-sig-formatter@1.0.11:
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
|
||||
integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
echarts-for-react@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/echarts-for-react/-/echarts-for-react-3.0.2.tgz#ac5859157048a1066d4553e34b328abb24f2b7c1"
|
||||
@@ -2154,6 +2202,11 @@ highlight.js@^11.9.0:
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.10.0.tgz#6e3600dc4b33d6dc23d5bd94fbf72405f5892b92"
|
||||
integrity sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==
|
||||
|
||||
http_ece@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/http_ece/-/http_ece-1.2.0.tgz#84d5885f052eae8c9b075eee4d2eb5105f114479"
|
||||
integrity sha512-JrF8SSLVmcvc5NducxgyOrKXe3EsyHMgBFgSaIUGmArKe+rwr0uphRkRXvwiom3I+fpIfoItveHrfudL8/rxuA==
|
||||
|
||||
https-proxy-agent@^5.0.0:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
|
||||
@@ -2162,6 +2215,14 @@ https-proxy-agent@^5.0.0:
|
||||
agent-base "6"
|
||||
debug "4"
|
||||
|
||||
https-proxy-agent@^7.0.0:
|
||||
version "7.0.5"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2"
|
||||
integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==
|
||||
dependencies:
|
||||
agent-base "^7.0.2"
|
||||
debug "4"
|
||||
|
||||
ignore@^5.2.0:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
|
||||
@@ -2188,7 +2249,7 @@ inflight@^1.0.4:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2, inherits@^2.0.3:
|
||||
inherits@2, inherits@^2.0.1, inherits@^2.0.3:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
@@ -2506,6 +2567,23 @@ json5@^1.0.2:
|
||||
object.assign "^4.1.4"
|
||||
object.values "^1.1.6"
|
||||
|
||||
jwa@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.0.tgz#a7e9c3f29dae94027ebcaf49975c9345593410fc"
|
||||
integrity sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==
|
||||
dependencies:
|
||||
buffer-equal-constant-time "1.0.1"
|
||||
ecdsa-sig-formatter "1.0.11"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
jws@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4"
|
||||
integrity sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==
|
||||
dependencies:
|
||||
jwa "^2.0.0"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
keyv@^4.5.3:
|
||||
version "4.5.4"
|
||||
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
|
||||
@@ -2617,6 +2695,11 @@ mimic-response@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43"
|
||||
integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==
|
||||
|
||||
minimalistic-assert@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
|
||||
integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
|
||||
|
||||
minimatch@9.0.3:
|
||||
version "9.0.3"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825"
|
||||
@@ -2638,7 +2721,7 @@ minimatch@^9.0.1, minimatch@^9.0.4:
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minimist@^1.2.0, minimist@^1.2.6:
|
||||
minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
|
||||
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
|
||||
@@ -3333,7 +3416,7 @@ safe-array-concat@^1.1.2:
|
||||
has-symbols "^1.0.3"
|
||||
isarray "^2.0.5"
|
||||
|
||||
safe-buffer@~5.2.0:
|
||||
safe-buffer@^5.0.1, safe-buffer@~5.2.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
@@ -3347,6 +3430,11 @@ safe-regex-test@^1.0.3:
|
||||
es-errors "^1.3.0"
|
||||
is-regex "^1.1.4"
|
||||
|
||||
safer-buffer@^2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
scheduler@^0.23.2:
|
||||
version "0.23.2"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3"
|
||||
@@ -3837,6 +3925,11 @@ undici-types@~5.26.4:
|
||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
|
||||
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
||||
|
||||
undici-types@~6.19.2:
|
||||
version "6.19.8"
|
||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02"
|
||||
integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
|
||||
@@ -3906,6 +3999,17 @@ victory-vendor@^36.6.8:
|
||||
d3-time "^3.0.0"
|
||||
d3-timer "^3.0.1"
|
||||
|
||||
web-push@^3.6.7:
|
||||
version "3.6.7"
|
||||
resolved "https://registry.yarnpkg.com/web-push/-/web-push-3.6.7.tgz#5f5e645951153e37ef90a6ddea5c150ea0f709e1"
|
||||
integrity sha512-OpiIUe8cuGjrj3mMBFWY+e4MMIkW3SVT+7vEIjvD9kejGUypv8GPDf84JdPWskK8zMRIJ6xYGm+Kxr8YkPyA0A==
|
||||
dependencies:
|
||||
asn1.js "^5.3.0"
|
||||
http_ece "1.2.0"
|
||||
https-proxy-agent "^7.0.0"
|
||||
jws "^4.0.0"
|
||||
minimist "^1.2.5"
|
||||
|
||||
webidl-conversions@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||
|
||||
Reference in New Issue
Block a user