mirror of
https://github.com/Drop-OSS/drop.git
synced 2025-11-13 00:02:37 +10:00
fix: etags and other
remove sanitize-filename because IDs are internally generated remove pulse animation on NO GAME cards add migration refactors to be inline with other stuff
This commit is contained in:
@ -21,6 +21,7 @@
|
|||||||
<SkeletonCard
|
<SkeletonCard
|
||||||
v-for="index in 10"
|
v-for="index in 10"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
:loading="true"
|
||||||
class="mr-3 flex-none"
|
class="mr-3 flex-none"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="rounded-lg w-48 h-64 bg-zinc-800/50 flex items-center justify-center transition-all duration-300 hover:bg-zinc-800 animate-pulse"
|
:class="[
|
||||||
|
'rounded-lg w-48 h-64 bg-zinc-800/50 flex items-center justify-center transition-all duration-300 hover:bg-zinc-800',
|
||||||
|
props.loading && 'animate-pulse',
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
<p class="text-zinc-700 text-sm font-semibold font-display uppercase">
|
<p class="text-zinc-700 text-sm font-semibold font-display uppercase">
|
||||||
{{ props.message }}
|
{{ props.message }}
|
||||||
@ -11,5 +14,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
message?: string;
|
message?: string;
|
||||||
|
loading?: boolean;
|
||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -33,7 +33,6 @@
|
|||||||
"nuxt": "^3.16.2",
|
"nuxt": "^3.16.2",
|
||||||
"nuxt-security": "2.2.0",
|
"nuxt-security": "2.2.0",
|
||||||
"prisma": "^6.5.0",
|
"prisma": "^6.5.0",
|
||||||
"sanitize-filename": "^1.6.3",
|
|
||||||
"sharp": "^0.33.5",
|
"sharp": "^0.33.5",
|
||||||
"stream-mime-type": "^2.0.0",
|
"stream-mime-type": "^2.0.0",
|
||||||
"turndown": "^7.2.0",
|
"turndown": "^7.2.0",
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "ObjectHash" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"hash" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "ObjectHash_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
@ -35,7 +35,7 @@ export default defineEventHandler(async (h3) => {
|
|||||||
throw createError({ statusCode: 400, statusMessage: "Image not found" });
|
throw createError({ statusCode: 400, statusMessage: "Image not found" });
|
||||||
|
|
||||||
game.mImageLibrary.splice(imageIndex, 1);
|
game.mImageLibrary.splice(imageIndex, 1);
|
||||||
await objectHandler.deleteAsServer(imageId);
|
await objectHandler.deleteAsSystem(imageId);
|
||||||
|
|
||||||
if (game.mBannerId === imageId) {
|
if (game.mBannerId === imageId) {
|
||||||
game.mBannerId = game.mImageLibrary[0];
|
game.mBannerId = game.mImageLibrary[0];
|
||||||
|
|||||||
@ -13,11 +13,12 @@ export default defineEventHandler(async (h3) => {
|
|||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/ETag
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/ETag
|
||||||
const etagRequestValue = h3.headers.get("If-None-Match");
|
const etagRequestValue = h3.headers.get("If-None-Match");
|
||||||
const etagActualValue = await objectHandler.fetchHashWithWithPermissions(
|
const etagActualValue = await objectHandler.fetchHash(id);
|
||||||
id,
|
if (
|
||||||
userId
|
etagRequestValue &&
|
||||||
);
|
etagActualValue &&
|
||||||
if (etagRequestValue !== null && etagActualValue === etagRequestValue) {
|
etagActualValue === etagRequestValue
|
||||||
|
) {
|
||||||
// would compare if etag is valid, but objects should never change
|
// would compare if etag is valid, but objects should never change
|
||||||
setResponseStatus(h3, 304);
|
setResponseStatus(h3, 304);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -14,10 +14,7 @@ export default defineEventHandler(async (h3) => {
|
|||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/ETag
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/ETag
|
||||||
const etagRequestValue = h3.headers.get("If-None-Match");
|
const etagRequestValue = h3.headers.get("If-None-Match");
|
||||||
const etagActualValue = await objectHandler.fetchHashWithWithPermissions(
|
const etagActualValue = await objectHandler.fetchHash(id);
|
||||||
id,
|
|
||||||
userId
|
|
||||||
);
|
|
||||||
if (etagRequestValue !== null && etagActualValue === etagRequestValue) {
|
if (etagRequestValue !== null && etagActualValue === etagRequestValue) {
|
||||||
// would compare if etag is valid, but objects should never change
|
// would compare if etag is valid, but objects should never change
|
||||||
setResponseStatus(h3, 304);
|
setResponseStatus(h3, 304);
|
||||||
|
|||||||
@ -129,7 +129,7 @@ class NewsManager {
|
|||||||
where: { id },
|
where: { id },
|
||||||
});
|
});
|
||||||
if (article.image) {
|
if (article.image) {
|
||||||
return await objectHandler.deleteAsServer(article.image);
|
return await objectHandler.deleteAsSystem(article.image);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import {
|
|||||||
Source,
|
Source,
|
||||||
} from "./objectHandler";
|
} from "./objectHandler";
|
||||||
|
|
||||||
import sanitize from "sanitize-filename";
|
|
||||||
import { LRUCache } from "lru-cache";
|
import { LRUCache } from "lru-cache";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
@ -30,12 +29,13 @@ export class FsObjectBackend extends ObjectBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fetch(id: ObjectReference) {
|
async fetch(id: ObjectReference) {
|
||||||
const objectPath = path.join(this.baseObjectPath, sanitize(id));
|
console.log("ID: " + id);
|
||||||
|
const objectPath = path.join(this.baseObjectPath, id);
|
||||||
if (!fs.existsSync(objectPath)) return undefined;
|
if (!fs.existsSync(objectPath)) return undefined;
|
||||||
return fs.createReadStream(objectPath);
|
return fs.createReadStream(objectPath);
|
||||||
}
|
}
|
||||||
async write(id: ObjectReference, source: Source): Promise<boolean> {
|
async write(id: ObjectReference, source: Source): Promise<boolean> {
|
||||||
const objectPath = path.join(this.baseObjectPath, sanitize(id));
|
const objectPath = path.join(this.baseObjectPath, id);
|
||||||
if (!fs.existsSync(objectPath)) return false;
|
if (!fs.existsSync(objectPath)) return false;
|
||||||
|
|
||||||
// remove item from cache
|
// remove item from cache
|
||||||
@ -56,7 +56,7 @@ export class FsObjectBackend extends ObjectBackend {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
async startWriteStream(id: ObjectReference) {
|
async startWriteStream(id: ObjectReference) {
|
||||||
const objectPath = path.join(this.baseObjectPath, sanitize(id));
|
const objectPath = path.join(this.baseObjectPath, id);
|
||||||
if (!fs.existsSync(objectPath)) return undefined;
|
if (!fs.existsSync(objectPath)) return undefined;
|
||||||
// remove item from cache
|
// remove item from cache
|
||||||
this.hashStore.delete(id);
|
this.hashStore.delete(id);
|
||||||
@ -67,11 +67,8 @@ export class FsObjectBackend extends ObjectBackend {
|
|||||||
source: Source,
|
source: Source,
|
||||||
metadata: ObjectMetadata
|
metadata: ObjectMetadata
|
||||||
): Promise<ObjectReference | undefined> {
|
): Promise<ObjectReference | undefined> {
|
||||||
const objectPath = path.join(this.baseObjectPath, sanitize(id));
|
const objectPath = path.join(this.baseObjectPath, id);
|
||||||
const metadataPath = path.join(
|
const metadataPath = path.join(this.baseMetadataPath, `${id}.json`);
|
||||||
this.baseMetadataPath,
|
|
||||||
`${sanitize(id)}.json`
|
|
||||||
);
|
|
||||||
if (fs.existsSync(objectPath) || fs.existsSync(metadataPath))
|
if (fs.existsSync(objectPath) || fs.existsSync(metadataPath))
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
||||||
@ -87,11 +84,8 @@ export class FsObjectBackend extends ObjectBackend {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
async createWithWriteStream(id: string, metadata: ObjectMetadata) {
|
async createWithWriteStream(id: string, metadata: ObjectMetadata) {
|
||||||
const objectPath = path.join(this.baseObjectPath, sanitize(id));
|
const objectPath = path.join(this.baseObjectPath, id);
|
||||||
const metadataPath = path.join(
|
const metadataPath = path.join(this.baseMetadataPath, `${id}.json`);
|
||||||
this.baseMetadataPath,
|
|
||||||
`${sanitize(id)}.json`
|
|
||||||
);
|
|
||||||
if (fs.existsSync(objectPath) || fs.existsSync(metadataPath))
|
if (fs.existsSync(objectPath) || fs.existsSync(metadataPath))
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
||||||
@ -101,10 +95,12 @@ export class FsObjectBackend extends ObjectBackend {
|
|||||||
// Create file so write passes
|
// Create file so write passes
|
||||||
fs.writeFileSync(objectPath, "");
|
fs.writeFileSync(objectPath, "");
|
||||||
|
|
||||||
return this.startWriteStream(id);
|
const stream = await this.startWriteStream(id);
|
||||||
|
if (!stream) throw new Error("Could not create write stream");
|
||||||
|
return stream;
|
||||||
}
|
}
|
||||||
async delete(id: ObjectReference): Promise<boolean> {
|
async delete(id: ObjectReference): Promise<boolean> {
|
||||||
const objectPath = path.join(this.baseObjectPath, sanitize(id));
|
const objectPath = path.join(this.baseObjectPath, id);
|
||||||
if (!fs.existsSync(objectPath)) return true;
|
if (!fs.existsSync(objectPath)) return true;
|
||||||
fs.rmSync(objectPath);
|
fs.rmSync(objectPath);
|
||||||
// remove item from cache
|
// remove item from cache
|
||||||
@ -114,10 +110,7 @@ export class FsObjectBackend extends ObjectBackend {
|
|||||||
async fetchMetadata(
|
async fetchMetadata(
|
||||||
id: ObjectReference
|
id: ObjectReference
|
||||||
): Promise<ObjectMetadata | undefined> {
|
): Promise<ObjectMetadata | undefined> {
|
||||||
const metadataPath = path.join(
|
const metadataPath = path.join(this.baseMetadataPath, `${id}.json`);
|
||||||
this.baseMetadataPath,
|
|
||||||
`${sanitize(id)}.json`
|
|
||||||
);
|
|
||||||
if (!fs.existsSync(metadataPath)) return undefined;
|
if (!fs.existsSync(metadataPath)) return undefined;
|
||||||
const metadata = JSON.parse(fs.readFileSync(metadataPath, "utf-8"));
|
const metadata = JSON.parse(fs.readFileSync(metadataPath, "utf-8"));
|
||||||
return metadata as ObjectMetadata;
|
return metadata as ObjectMetadata;
|
||||||
@ -126,16 +119,13 @@ export class FsObjectBackend extends ObjectBackend {
|
|||||||
id: ObjectReference,
|
id: ObjectReference,
|
||||||
metadata: ObjectMetadata
|
metadata: ObjectMetadata
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const metadataPath = path.join(
|
const metadataPath = path.join(this.baseMetadataPath, `${id}.json`);
|
||||||
this.baseMetadataPath,
|
|
||||||
`${sanitize(id)}.json`
|
|
||||||
);
|
|
||||||
if (!fs.existsSync(metadataPath)) return false;
|
if (!fs.existsSync(metadataPath)) return false;
|
||||||
fs.writeFileSync(metadataPath, JSON.stringify(metadata));
|
fs.writeFileSync(metadataPath, JSON.stringify(metadata));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
async fetchHash(id: ObjectReference): Promise<string | undefined> {
|
async fetchHash(id: ObjectReference): Promise<string | undefined> {
|
||||||
const cacheResult = this.hashStore.get(id);
|
const cacheResult = await this.hashStore.get(id);
|
||||||
if (cacheResult !== undefined) return cacheResult;
|
if (cacheResult !== undefined) return cacheResult;
|
||||||
|
|
||||||
const obj = await this.fetch(id);
|
const obj = await this.fetch(id);
|
||||||
@ -147,14 +137,18 @@ export class FsObjectBackend extends ObjectBackend {
|
|||||||
// hash object
|
// hash object
|
||||||
const hash = createHash("md5");
|
const hash = createHash("md5");
|
||||||
hash.setEncoding("hex");
|
hash.setEncoding("hex");
|
||||||
|
|
||||||
|
// read obj into hash
|
||||||
|
obj.pipe(hash);
|
||||||
|
await new Promise<void>((r) => {
|
||||||
obj.on("end", function () {
|
obj.on("end", function () {
|
||||||
hash.end();
|
hash.end();
|
||||||
cache.save(id, hash.read());
|
cache.save(id, hash.read());
|
||||||
|
r();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
// read obj into hash
|
|
||||||
obj.pipe(hash);
|
|
||||||
|
|
||||||
return this.hashStore.get(id);
|
return await this.hashStore.get(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +168,7 @@ class FsHashStore {
|
|||||||
const cacheRes = this.cache.get(id);
|
const cacheRes = this.cache.get(id);
|
||||||
if (cacheRes !== undefined) return cacheRes;
|
if (cacheRes !== undefined) return cacheRes;
|
||||||
|
|
||||||
const dbRes = await prisma.objectHash.findUnique({
|
const objectHash = await prisma.objectHash.findUnique({
|
||||||
where: {
|
where: {
|
||||||
id,
|
id,
|
||||||
},
|
},
|
||||||
@ -182,9 +176,9 @@ class FsHashStore {
|
|||||||
hash: true,
|
hash: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (dbRes === null) return undefined;
|
if (objectHash === null) return undefined;
|
||||||
this.cache.set(id, dbRes.hash);
|
this.cache.set(id, objectHash.hash);
|
||||||
return dbRes.hash;
|
return objectHash.hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -120,6 +120,32 @@ export class ObjectHandler {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We only need one permission, so find instead of filter is faster
|
||||||
|
private hasAnyPermissions(permissions: string[], userId?: string) {
|
||||||
|
return !!permissions.find((e) => {
|
||||||
|
if (userId !== undefined && e.startsWith(userId)) return true;
|
||||||
|
if (userId !== undefined && e.startsWith("internal")) return true;
|
||||||
|
if (e.startsWith("anonymous")) return true;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private fetchPermissions(permissions: string[], userId?: string) {
|
||||||
|
return (
|
||||||
|
permissions
|
||||||
|
.filter((e) => {
|
||||||
|
if (userId !== undefined && e.startsWith(userId)) return true;
|
||||||
|
if (userId !== undefined && e.startsWith("internal")) return true;
|
||||||
|
if (e.startsWith("anonymous")) return true;
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
// Strip IDs from permissions
|
||||||
|
.map((e) => e.split(":").at(1))
|
||||||
|
// Map to priority according to array
|
||||||
|
.map((e) => ObjectPermissionPriority.findIndex((c) => c === e))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches object, but also checks if user has perms to access it
|
* Fetches object, but also checks if user has perms to access it
|
||||||
* @param id object id
|
* @param id object id
|
||||||
@ -130,18 +156,7 @@ export class ObjectHandler {
|
|||||||
const metadata = await this.backend.fetchMetadata(id);
|
const metadata = await this.backend.fetchMetadata(id);
|
||||||
if (!metadata) return;
|
if (!metadata) return;
|
||||||
|
|
||||||
// We only need one permission, so find instead of filter is faster
|
if (!this.hasAnyPermissions(metadata.permissions, userId)) return;
|
||||||
const myPermissions = metadata.permissions.find((e) => {
|
|
||||||
if (userId !== undefined && e.startsWith(userId)) return true;
|
|
||||||
if (userId !== undefined && e.startsWith("internal")) return true;
|
|
||||||
if (e.startsWith("anonymous")) return true;
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!myPermissions) {
|
|
||||||
// We do not have access to this object
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Because any permission can be read or up, we automatically know we can read this object
|
// Because any permission can be read or up, we automatically know we can read this object
|
||||||
// So just straight return the object
|
// So just straight return the object
|
||||||
@ -155,30 +170,11 @@ export class ObjectHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch object hash, but also checks if user has perms to access it
|
* Fetch object hash. Permissions check should be done on read
|
||||||
* @param id object id
|
* @param id object id
|
||||||
* @param userId user to check, or act as anon user
|
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async fetchHashWithWithPermissions(id: ObjectReference, userId?: string) {
|
async fetchHash(id: ObjectReference) {
|
||||||
const metadata = await this.backend.fetchMetadata(id);
|
|
||||||
if (!metadata) return;
|
|
||||||
|
|
||||||
// We only need one permission, so find instead of filter is faster
|
|
||||||
const myPermissions = metadata.permissions.find((e) => {
|
|
||||||
if (userId !== undefined && e.startsWith(userId)) return true;
|
|
||||||
if (userId !== undefined && e.startsWith("internal")) return true;
|
|
||||||
if (e.startsWith("anonymous")) return true;
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!myPermissions) {
|
|
||||||
// We do not have access to this object
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Because any permission can be read or up, we automatically know we can read this object
|
|
||||||
// So just straight return the object
|
|
||||||
return await this.backend.fetchHash(id);
|
return await this.backend.fetchHash(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,21 +198,11 @@ export class ObjectHandler {
|
|||||||
const metadata = await this.backend.fetchMetadata(id);
|
const metadata = await this.backend.fetchMetadata(id);
|
||||||
if (!metadata) return false;
|
if (!metadata) return false;
|
||||||
|
|
||||||
const myPermissions = metadata.permissions
|
const permissions = this.fetchPermissions(metadata.permissions, userId);
|
||||||
.filter((e) => {
|
|
||||||
if (userId !== undefined && e.startsWith(userId)) return true;
|
|
||||||
if (userId !== undefined && e.startsWith("internal")) return true;
|
|
||||||
if (e.startsWith("anonymous")) return true;
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
// Strip IDs from permissions
|
|
||||||
.map((e) => e.split(":").at(1))
|
|
||||||
// Map to priority according to array
|
|
||||||
.map((e) => ObjectPermissionPriority.findIndex((c) => c === e));
|
|
||||||
|
|
||||||
const requiredPermissionIndex = 1;
|
const requiredPermissionIndex = 1;
|
||||||
const hasPermission =
|
const hasPermission =
|
||||||
myPermissions.find((e) => e >= requiredPermissionIndex) != undefined;
|
permissions.find((e) => e >= requiredPermissionIndex) != undefined;
|
||||||
|
|
||||||
if (!hasPermission) return false;
|
if (!hasPermission) return false;
|
||||||
|
|
||||||
@ -237,21 +223,11 @@ export class ObjectHandler {
|
|||||||
const metadata = await this.backend.fetchMetadata(id);
|
const metadata = await this.backend.fetchMetadata(id);
|
||||||
if (!metadata) return false;
|
if (!metadata) return false;
|
||||||
|
|
||||||
const myPermissions = metadata.permissions
|
const permissions = this.fetchPermissions(metadata.permissions, userId);
|
||||||
.filter((e) => {
|
|
||||||
if (userId !== undefined && e.startsWith(userId)) return true;
|
|
||||||
if (userId !== undefined && e.startsWith("internal")) return true;
|
|
||||||
if (e.startsWith("anonymous")) return true;
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
// Strip IDs from permissions
|
|
||||||
.map((e) => e.split(":").at(1))
|
|
||||||
// Map to priority according to array
|
|
||||||
.map((e) => ObjectPermissionPriority.findIndex((c) => c === e));
|
|
||||||
|
|
||||||
const requiredPermissionIndex = 2;
|
const requiredPermissionIndex = 2;
|
||||||
const hasPermission =
|
const hasPermission =
|
||||||
myPermissions.find((e) => e >= requiredPermissionIndex) != undefined;
|
permissions.find((e) => e >= requiredPermissionIndex) != undefined;
|
||||||
|
|
||||||
if (!hasPermission) return false;
|
if (!hasPermission) return false;
|
||||||
|
|
||||||
@ -264,7 +240,7 @@ export class ObjectHandler {
|
|||||||
* @param id
|
* @param id
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async deleteAsServer(id: ObjectReference) {
|
async deleteAsSystem(id: ObjectReference) {
|
||||||
return await this.backend.delete(id);
|
return await this.backend.delete(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,7 +62,7 @@ class SaveManager {
|
|||||||
await Promise.all([hashPromise, uploadStream]);
|
await Promise.all([hashPromise, uploadStream]);
|
||||||
|
|
||||||
if (!hash) {
|
if (!hash) {
|
||||||
await objectHandler.deleteAsServer(newSaveObjectId);
|
await objectHandler.deleteAsSystem(newSaveObjectId);
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: 500,
|
statusCode: 500,
|
||||||
statusMessage: "Hash failed to generate",
|
statusMessage: "Hash failed to generate",
|
||||||
|
|||||||
19
yarn.lock
19
yarn.lock
@ -5291,13 +5291,6 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0:
|
|||||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||||
|
|
||||||
sanitize-filename@^1.6.3:
|
|
||||||
version "1.6.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/sanitize-filename/-/sanitize-filename-1.6.3.tgz#755ebd752045931977e30b2025d340d7c9090378"
|
|
||||||
integrity sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==
|
|
||||||
dependencies:
|
|
||||||
truncate-utf8-bytes "^1.0.0"
|
|
||||||
|
|
||||||
sass@^1.79.4:
|
sass@^1.79.4:
|
||||||
version "1.86.0"
|
version "1.86.0"
|
||||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.86.0.tgz#f49464fb6237a903a93f4e8760ef6e37a5030114"
|
resolved "https://registry.yarnpkg.com/sass/-/sass-1.86.0.tgz#f49464fb6237a903a93f4e8760ef6e37a5030114"
|
||||||
@ -5845,13 +5838,6 @@ tr46@~0.0.3:
|
|||||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||||
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
|
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
|
||||||
|
|
||||||
truncate-utf8-bytes@^1.0.0:
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b"
|
|
||||||
integrity sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==
|
|
||||||
dependencies:
|
|
||||||
utf8-byte-length "^1.0.1"
|
|
||||||
|
|
||||||
tslib@^2.4.0, tslib@^2.8.0:
|
tslib@^2.4.0, tslib@^2.8.0:
|
||||||
version "2.8.1"
|
version "2.8.1"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
||||||
@ -6105,11 +6091,6 @@ uqr@^0.1.2:
|
|||||||
resolved "https://registry.yarnpkg.com/uqr/-/uqr-0.1.2.tgz#5c6cd5dcff9581f9bb35b982cb89e2c483a41d7d"
|
resolved "https://registry.yarnpkg.com/uqr/-/uqr-0.1.2.tgz#5c6cd5dcff9581f9bb35b982cb89e2c483a41d7d"
|
||||||
integrity sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==
|
integrity sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==
|
||||||
|
|
||||||
utf8-byte-length@^1.0.1:
|
|
||||||
version "1.0.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz#f9f63910d15536ee2b2d5dd4665389715eac5c1e"
|
|
||||||
integrity sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==
|
|
||||||
|
|
||||||
util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
|
util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||||
|
|||||||
Reference in New Issue
Block a user