From 297287973c53ec131f4c0ed026d6053a3183a9ad Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 12 Jul 2024 17:30:03 -0400 Subject: [PATCH 001/188] Font size --- website/pastebook/src/components/Content.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/pastebook/src/components/Content.svelte b/website/pastebook/src/components/Content.svelte index dfca58a..3edb278 100644 --- a/website/pastebook/src/components/Content.svelte +++ b/website/pastebook/src/components/Content.svelte @@ -348,7 +348,7 @@ } @media (max-width: 600px){ - font-size: 11px; + font-size: 10px; padding-left: 30px; text-indent: -18px; } From 06505497680bf4f6bf7564662f71aa43b1854646 Mon Sep 17 00:00:00 2001 From: matytyma Date: Fri, 26 Jul 2024 19:40:11 +0200 Subject: [PATCH 002/188] Fix website link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6594769..2e8f255 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

PasteBook

PasteBook is an aesthetic, effortless way to share your blocks of text, and respects your privacy by automatically deleting your pastes.

- ![Static Badge](https://img.shields.io/badge/Website-brightgreen?style=for-the-badge&link=https%3A%2F%2Fpastebook.dev) + [![Static Badge](https://img.shields.io/badge/Website-brightgreen?style=for-the-badge)](https://pastebook.dev) From ecf86c6270e4be07171874d7f3bc9d00aa94eae1 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Sun, 28 Jul 2024 23:13:28 -0400 Subject: [PATCH 003/188] Title --- website/pastebook/src/routes/pastes/[slug]/+page.svelte | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/pastebook/src/routes/pastes/[slug]/+page.svelte b/website/pastebook/src/routes/pastes/[slug]/+page.svelte index 7816c35..8eab361 100644 --- a/website/pastebook/src/routes/pastes/[slug]/+page.svelte +++ b/website/pastebook/src/routes/pastes/[slug]/+page.svelte @@ -64,6 +64,8 @@ hashedIP = data.user.hashedIP expires = new Date(data.expiresAt) + document.title = title + " • PasteBook" + const reloadTime = () => { timeSinceStr = formatTimeSince(created) untilExpire = formatTimeUntil(expires) From c7588b8429fb89ecb1faa1d457dc0af6430609f7 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Sun, 28 Jul 2024 23:15:09 -0400 Subject: [PATCH 004/188] Run on mount --- website/pastebook/src/routes/pastes/[slug]/+page.svelte | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/pastebook/src/routes/pastes/[slug]/+page.svelte b/website/pastebook/src/routes/pastes/[slug]/+page.svelte index 8eab361..bc2b1b4 100644 --- a/website/pastebook/src/routes/pastes/[slug]/+page.svelte +++ b/website/pastebook/src/routes/pastes/[slug]/+page.svelte @@ -64,8 +64,6 @@ hashedIP = data.user.hashedIP expires = new Date(data.expiresAt) - document.title = title + " • PasteBook" - const reloadTime = () => { timeSinceStr = formatTimeSince(created) untilExpire = formatTimeUntil(expires) @@ -83,6 +81,7 @@ onMount(() => { document.addEventListener('mousemove', onMouseUpdate, false); document.addEventListener('mouseenter', onMouseUpdate, false); + document.title = title + " • PasteBook" function onMouseUpdate(e) { x = e.pageX; From d540835ae1213824fb95eafcb20860a9eaf579ef Mon Sep 17 00:00:00 2001 From: Loudbook Date: Sun, 28 Jul 2024 23:17:21 -0400 Subject: [PATCH 005/188] Change location --- website/pastebook/src/routes/pastes/[slug]/+page.svelte | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/website/pastebook/src/routes/pastes/[slug]/+page.svelte b/website/pastebook/src/routes/pastes/[slug]/+page.svelte index bc2b1b4..a0ff89b 100644 --- a/website/pastebook/src/routes/pastes/[slug]/+page.svelte +++ b/website/pastebook/src/routes/pastes/[slug]/+page.svelte @@ -73,6 +73,10 @@ let clear clearInterval(clear) clear = setInterval(reloadTime, 1000) + + onMount(() => { + document.title = title + " • PasteBook" + }) }); let x = null; @@ -81,7 +85,6 @@ onMount(() => { document.addEventListener('mousemove', onMouseUpdate, false); document.addEventListener('mouseenter', onMouseUpdate, false); - document.title = title + " • PasteBook" function onMouseUpdate(e) { x = e.pageX; From a3b4aba77317c45628b45780b731af9c2b3f249c Mon Sep 17 00:00:00 2001 From: Loudbook Date: Sun, 28 Jul 2024 23:18:48 -0400 Subject: [PATCH 006/188] Run in load handler --- .../pastebook/src/routes/pastes/[slug]/+page.svelte | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/website/pastebook/src/routes/pastes/[slug]/+page.svelte b/website/pastebook/src/routes/pastes/[slug]/+page.svelte index a0ff89b..31b4013 100644 --- a/website/pastebook/src/routes/pastes/[slug]/+page.svelte +++ b/website/pastebook/src/routes/pastes/[slug]/+page.svelte @@ -73,10 +73,6 @@ let clear clearInterval(clear) clear = setInterval(reloadTime, 1000) - - onMount(() => { - document.title = title + " • PasteBook" - }) }); let x = null; @@ -135,6 +131,10 @@ idElement.style.opacity = 0 idElement.style.height = "0" } + + function loadHandler() { + document.title = title + " • PasteBook" + }
@@ -144,7 +144,7 @@ - - -PasteBook was created with the intention of being used as a quick-and-easy solution to sharing temporary data with others. From 28ab6ee8c418e77aab44beb5d63f35a1d047d5ee Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 4 Oct 2024 21:25:27 -0400 Subject: [PATCH 015/188] Remove Discord hook --- .../dev/loudbook/pastebook/DeleteHandler.kt | 4 - .../kotlin/dev/loudbook/pastebook/Discord.kt | 78 ------------------- .../pastebook/PasteBookApplication.kt | 17 ---- .../pastebook/config/Configuration.kt | 14 ---- .../pastebook/controllers/UploadController.kt | 18 +---- .../dev/loudbook/pastebook/data/Paste.kt | 2 +- .../pastebook/data/PastePrivateDTO.kt | 2 +- 7 files changed, 3 insertions(+), 132 deletions(-) delete mode 100644 src/main/kotlin/dev/loudbook/pastebook/Discord.kt diff --git a/src/main/kotlin/dev/loudbook/pastebook/DeleteHandler.kt b/src/main/kotlin/dev/loudbook/pastebook/DeleteHandler.kt index 401c53b..91391f6 100644 --- a/src/main/kotlin/dev/loudbook/pastebook/DeleteHandler.kt +++ b/src/main/kotlin/dev/loudbook/pastebook/DeleteHandler.kt @@ -45,10 +45,6 @@ class DeleteHandler { } for (paste in deletablePastes) { - if (!paste.unlisted) { - discord.delete(paste.discordID.toString()) - } - pasteRepository.delete(paste) paste.id?.let { r2Service.deleteFile(it) } ?: println("Failed to delete paste; $paste") } diff --git a/src/main/kotlin/dev/loudbook/pastebook/Discord.kt b/src/main/kotlin/dev/loudbook/pastebook/Discord.kt deleted file mode 100644 index f743147..0000000 --- a/src/main/kotlin/dev/loudbook/pastebook/Discord.kt +++ /dev/null @@ -1,78 +0,0 @@ -package dev.loudbook.pastebook - -import com.google.gson.JsonParser -import org.springframework.stereotype.Component -import java.net.URI -import java.net.http.HttpClient -import java.net.http.HttpRequest -import java.net.http.HttpResponse -import java.util.* -import kotlin.concurrent.schedule - -@Component -class Discord(private val properties: Properties) { - final fun send(name: String, pastebookURL: String, pasteGGURL: String?, expireTime: Long): String { - val content = if (pasteGGURL != null) { - "New paste created (${name}): [PasteBook](<${pastebookURL}>) | [PasteGG](${pasteGGURL})\\n\\nExpires " - } else { - "New paste created: [${name}](<${pastebookURL}>)\\n\\nExpires " - } - - val jsonStr = """ - { - "content": "$content", - "allowed_mentions": { - "parse": [] - } - } - """.trimIndent() - - val discordURL = properties.getProperty("url") - println(jsonStr) - - val client = HttpClient.newBuilder().build() - val request = HttpRequest.newBuilder() - .uri(URI.create("$discordURL?wait=true")) - .header("Content-Type", "application/json") - .POST(HttpRequest.BodyPublishers.ofString(jsonStr)) - .build() - val response = client.send(request, HttpResponse.BodyHandlers.ofString()) - - val json = response.body() - val jsonObject = JsonParser.parseString(json).asJsonObject - - return jsonObject.get("id").asString - } - - - fun delete(id: String) { - val discordURL = properties.getProperty("url") - val deleteURL = "$discordURL/messages/$id" - - val client = HttpClient.newBuilder().build() - val request = HttpRequest.newBuilder() - .uri(URI.create(deleteURL)) - .DELETE() - .build() - val response = client.send(request, HttpResponse.BodyHandlers.ofString()) - - try { - val jsonResponse = JsonParser.parseString(response.body()).asJsonObject - val message = jsonResponse.get("message").asString - - if (message != null && message.contains("rate limited")) { - println("Rate limited, retrying in 3 seconds") - Timer().schedule(3500) { - println("Retrying delete of $id") - delete(id) - } - } - } catch (e: IllegalStateException) { - println("Failed to delete $id") - } catch (e: NullPointerException) { - println("Failed to delete $id") - } - - println(response.body()) - } -} \ No newline at end of file diff --git a/src/main/kotlin/dev/loudbook/pastebook/PasteBookApplication.kt b/src/main/kotlin/dev/loudbook/pastebook/PasteBookApplication.kt index 4e998c4..8a42001 100644 --- a/src/main/kotlin/dev/loudbook/pastebook/PasteBookApplication.kt +++ b/src/main/kotlin/dev/loudbook/pastebook/PasteBookApplication.kt @@ -2,30 +2,13 @@ package dev.loudbook.pastebook import org.springframework.boot.SpringApplication import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.context.ApplicationContextInitializer -import org.springframework.context.support.GenericApplicationContext import org.springframework.data.mongodb.repository.config.EnableMongoRepositories -import java.nio.file.Files -import java.nio.file.Paths -import java.util.* -import java.util.function.Supplier @SpringBootApplication @EnableMongoRepositories class PasteBookApplication -val discord = Discord(Properties().apply { - load(Files.newBufferedReader(Paths.get("./config.properties"))) -}) - fun main(args: Array) { val application = SpringApplication(PasteBookApplication::class.java) - - application.addInitializers(ApplicationContextInitializer { ctx: GenericApplicationContext -> - ctx.registerBean( - Discord::class.java, - Supplier { discord }) - }) - application.run(*args) } \ No newline at end of file diff --git a/src/main/kotlin/dev/loudbook/pastebook/config/Configuration.kt b/src/main/kotlin/dev/loudbook/pastebook/config/Configuration.kt index 7aac27c..7a39ce4 100644 --- a/src/main/kotlin/dev/loudbook/pastebook/config/Configuration.kt +++ b/src/main/kotlin/dev/loudbook/pastebook/config/Configuration.kt @@ -1,25 +1,11 @@ package dev.loudbook.pastebook.config import dev.loudbook.pastebook.DeleteHandler -import dev.loudbook.pastebook.Discord import org.springframework.context.annotation.Bean import org.springframework.stereotype.Component -import java.nio.file.Files -import java.nio.file.Paths -import java.util.* @Component class Configuration { - @Bean - fun discord() = Discord(properties()) - @Bean fun deleteHandler() = DeleteHandler() - - fun properties(): Properties { - val properties = Properties() - properties.load(Files.newBufferedReader(Paths.get("./config.properties"))) - - return properties - } } \ No newline at end of file diff --git a/src/main/kotlin/dev/loudbook/pastebook/controllers/UploadController.kt b/src/main/kotlin/dev/loudbook/pastebook/controllers/UploadController.kt index 50a0b7f..2562a06 100644 --- a/src/main/kotlin/dev/loudbook/pastebook/controllers/UploadController.kt +++ b/src/main/kotlin/dev/loudbook/pastebook/controllers/UploadController.kt @@ -2,7 +2,6 @@ package dev.loudbook.pastebook.controllers import dev.loudbook.pastebook.BucketUtils import dev.loudbook.pastebook.ContentScanner -import dev.loudbook.pastebook.Discord import dev.loudbook.pastebook.IPUtils import dev.loudbook.pastebook.data.PastePrivateDTO import dev.loudbook.pastebook.data.R2Service @@ -19,9 +18,6 @@ import org.springframework.web.bind.annotation.RestController @RestController class UploadController { - @Autowired - private lateinit var discord: Discord - @Autowired lateinit var r2Service: R2Service @@ -71,21 +67,9 @@ class UploadController { val ip = IPUtils.getIPFromRequest(request) ?: return ResponseEntity.badRequest().body("Failed to get IP") - val paste = PastePrivateDTO(fileID, title, sinceTheEpoch, null, reportBook, unlisted, wrap, ip, expire) + val paste = PastePrivateDTO(fileID, title, sinceTheEpoch, reportBook, unlisted, wrap, ip, expire) val pastebookURL = uploadPastebook(paste) ?: return ResponseEntity.badRequest().body("Failed to upload pastebook") - val discordID = try { - if (!unlisted) { - discord.send(title, pastebookURL, null, expire / 1000L).toLong() - } else { - 0L - } - } catch (_: NullPointerException) { - 0L - } - - paste.discordID = discordID - r2Service.uploadFile(fileID, filteredBody) pasteRepository.save(paste) diff --git a/src/main/kotlin/dev/loudbook/pastebook/data/Paste.kt b/src/main/kotlin/dev/loudbook/pastebook/data/Paste.kt index 545c31a..2de1d7c 100644 --- a/src/main/kotlin/dev/loudbook/pastebook/data/Paste.kt +++ b/src/main/kotlin/dev/loudbook/pastebook/data/Paste.kt @@ -5,4 +5,4 @@ import org.springframework.data.mongodb.core.mapping.Document @Suppress("unused") @Document("paste") -class Paste(@Id var id: String?, val title: String, val content: String, val created: Long, var discordID : Long?, val reportBook: Boolean = false, val unlisted: Boolean = false, val wrap: Boolean = false, val creatorIP: String) \ No newline at end of file +class Paste(@Id var id: String?, val title: String, val content: String, val created: Long, val reportBook: Boolean = false, val unlisted: Boolean = false, val wrap: Boolean = false, val creatorIP: String) \ No newline at end of file diff --git a/src/main/kotlin/dev/loudbook/pastebook/data/PastePrivateDTO.kt b/src/main/kotlin/dev/loudbook/pastebook/data/PastePrivateDTO.kt index 9afe2c3..cd7665f 100644 --- a/src/main/kotlin/dev/loudbook/pastebook/data/PastePrivateDTO.kt +++ b/src/main/kotlin/dev/loudbook/pastebook/data/PastePrivateDTO.kt @@ -3,6 +3,6 @@ package dev.loudbook.pastebook.data import org.springframework.data.annotation.Id @Suppress("unused") -data class PastePrivateDTO(@Id var id: String?, val title: String, val created: Long, var discordID: Long?, val reportBook: Boolean = false, val unlisted: Boolean = false, val wrap: Boolean = false, val creatorIP: String, val expires: Long){ +data class PastePrivateDTO(@Id var id: String?, val title: String, val created: Long, val reportBook: Boolean = false, val unlisted: Boolean = false, val wrap: Boolean = false, val creatorIP: String, val expires: Long){ fun toPublicDTO(user: UserDTO) = PasteDTO(id, user, title, created, reportBook, unlisted, wrap, expires) } \ No newline at end of file From 66aebdc710424c5116d7318745da31db1cd79d93 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 4 Oct 2024 21:43:24 -0400 Subject: [PATCH 016/188] Unselect line --- website/pastebook/src/components/Content.svelte | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/website/pastebook/src/components/Content.svelte b/website/pastebook/src/components/Content.svelte index 3edb278..911566f 100755 --- a/website/pastebook/src/components/Content.svelte +++ b/website/pastebook/src/components/Content.svelte @@ -153,6 +153,13 @@ } function updateLineView(newLine: number) { + if (currentScrolledLine === newLine) { + currentScrolledLine = 0 + removeCurrentScrolledLine() + + return; + } + let newLineElement = document.getElementById("line-container-" + newLine) let newLineElementNumber = document.getElementById("line-number-" + newLine) @@ -194,6 +201,16 @@ } }) + function removeCurrentScrolledLine() { + let currentLine = document.getElementById("line-container-" + currentScrolledLine) + let currentLineNumber = document.getElementById("line-number-" + currentScrolledLine) + + currentLine.style.marginTop = "0px" + currentLine.style.marginBottom = "0px" + + currentLineNumber.style.fontWeight = "normal" + } + function clickNumber(event: MouseEvent) { let element = event.currentTarget as HTMLElement From 1bd2c39103f2cfa04781fdbe595e161664feb1b5 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Thu, 10 Oct 2024 21:48:20 -0400 Subject: [PATCH 017/188] Refactor & Cookie Inspection Control --- src/main/resources/application.yml | 4 + website/pastebook/.prettierrc | 5 + website/pastebook/package-lock.json | 4747 +++++++++-------- website/pastebook/package.json | 66 +- website/pastebook/src/app.d.ts | 3 +- website/pastebook/src/app.html | 66 +- website/pastebook/src/components/Beta.svelte | 52 +- .../pastebook/src/components/Content.svelte | 442 +- .../pastebook/src/components/Header.svelte | 42 +- .../pastebook/src/components/Highlight.svelte | 132 +- website/pastebook/src/components/Mode.svelte | 82 +- .../src/components/PotentialIssues.svelte | 109 +- .../pastebook/src/components/Toolbar.svelte | 60 +- .../src/components/new/Submit.svelte | 227 +- .../src/components/panel/ListedPaste.svelte | 63 +- .../src/components/pulltab/Pulltab.svelte | 77 +- .../src/components/settings/DropDown.svelte | 17 +- .../src/components/settings/Setting.svelte | 21 +- .../src/components/settings/Switch.svelte | 51 +- website/pastebook/src/lib/detections.json | 2 +- website/pastebook/src/lib/issue.ts | 2 +- website/pastebook/src/lib/paste.ts | 18 +- website/pastebook/src/lib/stores.ts | 6 +- website/pastebook/src/lib/timehandler.ts | 130 +- website/pastebook/src/params/paste.ts | 2 +- website/pastebook/src/routes/+error.svelte | 70 +- website/pastebook/src/routes/+layout.svelte | 8 +- website/pastebook/src/routes/+page.svelte | 103 +- .../[pastes=paste]/[slug]/+page.server.ts | 85 +- .../routes/[pastes=paste]/[slug]/+page.svelte | 322 +- website/pastebook/src/routes/new/+page.svelte | 196 +- .../src/routes/panel/+page.server.ts | 35 +- .../pastebook/src/routes/panel/+page.svelte | 179 +- .../pastebook/src/routes/privacy/+page.svelte | 1991 +++---- .../src/routes/settings/+page.svelte | 289 +- website/pastebook/svelte.config.js | 16 +- website/pastebook/tsconfig.json | 36 +- website/pastebook/vite.config.ts | 6 +- 38 files changed, 5042 insertions(+), 4720 deletions(-) create mode 100644 src/main/resources/application.yml create mode 100644 website/pastebook/.prettierrc diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..c094208 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,4 @@ +s3: + accessKey: "c811d8f01abd565921106aa8909c31e1" + secretKey: "0325393687899e83a6d3d11d60079830ca47bdbf99210e50f3050699c7213f96" + url: "https://3364c2b7baa43c93ad91daf56989f1d0.r2.cloudflarestorage.com" \ No newline at end of file diff --git a/website/pastebook/.prettierrc b/website/pastebook/.prettierrc new file mode 100644 index 0000000..ca43d6f --- /dev/null +++ b/website/pastebook/.prettierrc @@ -0,0 +1,5 @@ +{ + "plugins": ["prettier-plugin-svelte"], + "pluginSearchDirs": ["."], + "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] +} diff --git a/website/pastebook/package-lock.json b/website/pastebook/package-lock.json index bc813bf..4c7d193 100644 --- a/website/pastebook/package-lock.json +++ b/website/pastebook/package-lock.json @@ -1,2361 +1,2390 @@ { - "name": "pastebook", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "pastebook", - "version": "0.0.1", - "dependencies": { - "just-extend": "^6.2.0" - }, - "devDependencies": { - "@fontsource/fira-mono": "^4.5.10", - "@neoconfetti/svelte": "^1.0.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@sveltejs/adapter-auto": "^3.0.0", - "@sveltejs/adapter-node": "^5.0.1", - "@sveltejs/adapter-static": "^3.0.1", - "@sveltejs/kit": "^2.0.0", - "@sveltejs/vite-plugin-svelte": "^3.0.0", - "@types/node": "^20.12.7", - "rollup": "^4.14.3", - "rollup-plugin-svelte": "^7.2.0", - "sass": "^1.74.1", - "svelte": "^4.2.19", - "svelte-check": "^3.6.0", - "tslib": "^2.4.1", - "typescript": "^5.0.0", - "vite": "^5.0.3" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@fontsource/fira-mono": { - "version": "4.5.10", - "resolved": "https://registry.npmjs.org/@fontsource/fira-mono/-/fira-mono-4.5.10.tgz", - "integrity": "sha512-bxUnRP8xptGRo8YXeY073DSpfK74XpSb0ZyRNpHV9WvLnJ7TwPOjZll8hTMin7zLC6iOp59pDZ8EQDj1gzgAQQ==", - "dev": true - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@neoconfetti/svelte": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@neoconfetti/svelte/-/svelte-1.0.0.tgz", - "integrity": "sha512-SmksyaJAdSlMa9cTidVSIqYo1qti+WTsviNDwgjNVm+KQ3DRP2Df9umDIzC4vCcpEYY+chQe0i2IKnLw03AT8Q==", - "dev": true - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@polka/url": { - "version": "1.0.0-next.25", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz", - "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==", - "dev": true - }, - "node_modules/@rollup/plugin-commonjs": { - "version": "25.0.7", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz", - "integrity": "sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "commondir": "^1.0.1", - "estree-walker": "^2.0.2", - "glob": "^8.0.3", - "is-reference": "1.2.1", - "magic-string": "^0.30.3" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.68.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-commonjs/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@rollup/plugin-commonjs/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, - "node_modules/@rollup/plugin-commonjs/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@rollup/plugin-commonjs/node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/@rollup/plugin-commonjs/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@rollup/plugin-json": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", - "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^5.1.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "15.2.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", - "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.2.1", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", - "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.3.tgz", - "integrity": "sha512-X9alQ3XM6I9IlSlmC8ddAvMSyG1WuHk5oUnXGw+yUBs3BFoTizmG1La/Gr8fVJvDWAq+zlYTZ9DBgrlKRVY06g==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.3.tgz", - "integrity": "sha512-eQK5JIi+POhFpzk+LnjKIy4Ks+pwJ+NXmPxOCSvOKSNRPONzKuUvWE+P9JxGZVxrtzm6BAYMaL50FFuPe0oWMQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.3.tgz", - "integrity": "sha512-Od4vE6f6CTT53yM1jgcLqNfItTsLt5zE46fdPaEmeFHvPs5SjZYlLpHrSiHEKR1+HdRfxuzXHjDOIxQyC3ptBA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.3.tgz", - "integrity": "sha512-0IMAO21axJeNIrvS9lSe/PGthc8ZUS+zC53O0VhF5gMxfmcKAP4ESkKOCwEi6u2asUrt4mQv2rjY8QseIEb1aw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.3.tgz", - "integrity": "sha512-ge2DC7tHRHa3caVEoSbPRJpq7azhG+xYsd6u2MEnJ6XzPSzQsTKyXvh6iWjXRf7Rt9ykIUWHtl0Uz3T6yXPpKw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.14.3.tgz", - "integrity": "sha512-ljcuiDI4V3ySuc7eSk4lQ9wU8J8r8KrOUvB2U+TtK0TiW6OFDmJ+DdIjjwZHIw9CNxzbmXY39wwpzYuFDwNXuw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.3.tgz", - "integrity": "sha512-Eci2us9VTHm1eSyn5/eEpaC7eP/mp5n46gTRB3Aar3BgSvDQGJZuicyq6TsH4HngNBgVqC5sDYxOzTExSU+NjA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.3.tgz", - "integrity": "sha512-UrBoMLCq4E92/LCqlh+blpqMz5h1tJttPIniwUgOFJyjWI1qrtrDhhpHPuFxULlUmjFHfloWdixtDhSxJt5iKw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.3.tgz", - "integrity": "sha512-5aRjvsS8q1nWN8AoRfrq5+9IflC3P1leMoy4r2WjXyFqf3qcqsxRCfxtZIV58tCxd+Yv7WELPcO9mY9aeQyAmw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.3.tgz", - "integrity": "sha512-sk/Qh1j2/RJSX7FhEpJn8n0ndxy/uf0kI/9Zc4b1ELhqULVdTfN6HL31CDaTChiBAOgLcsJ1sgVZjWv8XNEsAQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.3.tgz", - "integrity": "sha512-jOO/PEaDitOmY9TgkxF/TQIjXySQe5KVYB57H/8LRP/ux0ZoO8cSHCX17asMSv3ruwslXW/TLBcxyaUzGRHcqg==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.3.tgz", - "integrity": "sha512-8ybV4Xjy59xLMyWo3GCfEGqtKV5M5gCSrZlxkPGvEPCGDLNla7v48S662HSGwRd6/2cSneMQWiv+QzcttLrrOA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.3.tgz", - "integrity": "sha512-s+xf1I46trOY10OqAtZ5Rm6lzHre/UiLA1J2uOhCFXWkbZrJRkYBPO6FhvGfHmdtQ3Bx793MNa7LvoWFAm93bg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.3.tgz", - "integrity": "sha512-+4h2WrGOYsOumDQ5S2sYNyhVfrue+9tc9XcLWLh+Kw3UOxAvrfOrSMFon60KspcDdytkNDh7K2Vs6eMaYImAZg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.3.tgz", - "integrity": "sha512-T1l7y/bCeL/kUwh9OD4PQT4aM7Bq43vX05htPJJ46RTI4r5KNt6qJRzAfNfM+OYMNEVBWQzR2Gyk+FXLZfogGw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.3.tgz", - "integrity": "sha512-/BypzV0H1y1HzgYpxqRaXGBRqfodgoBBCcsrujT6QRcakDQdfU+Lq9PENPh5jB4I44YWq+0C2eHsHya+nZY1sA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@sveltejs/adapter-auto": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-3.2.0.tgz", - "integrity": "sha512-She5nKT47kwHE18v9NMe6pbJcvULr82u0V3yZ0ej3n1laWKGgkgdEABE9/ak5iDPs93LqsBkuIo51kkwCLBjJA==", - "dev": true, - "dependencies": { - "import-meta-resolve": "^4.0.0" - }, - "peerDependencies": { - "@sveltejs/kit": "^2.0.0" - } - }, - "node_modules/@sveltejs/adapter-node": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.0.1.tgz", - "integrity": "sha512-eYdmxdUWMW+dad1JfMsWBPY2vjXz9eE+52A2AQnXPScPJlIxIVk5mmbaEEzrZivLfO2wEcLTZ5vdC03W69x+iA==", - "dev": true, - "dependencies": { - "@rollup/plugin-commonjs": "^25.0.7", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "rollup": "^4.9.5" - }, - "peerDependencies": { - "@sveltejs/kit": "^2.4.0" - } - }, - "node_modules/@sveltejs/adapter-static": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.1.tgz", - "integrity": "sha512-6lMvf7xYEJ+oGeR5L8DFJJrowkefTK6ZgA4JiMqoClMkKq0s6yvsd3FZfCFvX1fQ0tpCD7fkuRVHsnUVgsHyNg==", - "dev": true, - "peerDependencies": { - "@sveltejs/kit": "^2.0.0" - } - }, - "node_modules/@sveltejs/kit": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.5.tgz", - "integrity": "sha512-ULe3PB00q4+wYRL+IS5FDPsCEVnhEITofm7b9Yz8malcH3r1SAnW/JJ6T13hIMeu8QNRIuVQWo+P4+2VklbnLQ==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@types/cookie": "^0.6.0", - "cookie": "^0.6.0", - "devalue": "^4.3.2", - "esm-env": "^1.0.0", - "import-meta-resolve": "^4.0.0", - "kleur": "^4.1.5", - "magic-string": "^0.30.5", - "mrmime": "^2.0.0", - "sade": "^1.8.1", - "set-cookie-parser": "^2.6.0", - "sirv": "^2.0.4", - "tiny-glob": "^0.2.9" - }, - "bin": { - "svelte-kit": "svelte-kit.js" - }, - "engines": { - "node": ">=18.13" - }, - "peerDependencies": { - "@sveltejs/vite-plugin-svelte": "^3.0.0", - "svelte": "^4.0.0 || ^5.0.0-next.0", - "vite": "^5.0.3" - } - }, - "node_modules/@sveltejs/vite-plugin-svelte": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.0.tgz", - "integrity": "sha512-sY6ncCvg+O3njnzbZexcVtUqOBE3iYmQPJ9y+yXSkOwG576QI/xJrBnQSRXFLGwJNBa0T78JEKg5cIR0WOAuUw==", - "dev": true, - "dependencies": { - "@sveltejs/vite-plugin-svelte-inspector": "^2.0.0", - "debug": "^4.3.4", - "deepmerge": "^4.3.1", - "kleur": "^4.1.5", - "magic-string": "^0.30.9", - "svelte-hmr": "^0.16.0", - "vitefu": "^0.2.5" - }, - "engines": { - "node": "^18.0.0 || >=20" - }, - "peerDependencies": { - "svelte": "^4.0.0 || ^5.0.0-next.0", - "vite": "^5.0.0" - } - }, - "node_modules/@sveltejs/vite-plugin-svelte-inspector": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.1.0.tgz", - "integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.0.0 || >=20" - }, - "peerDependencies": { - "@sveltejs/vite-plugin-svelte": "^3.0.0", - "svelte": "^4.0.0 || ^5.0.0-next.0", - "vite": "^5.0.0" - } - }, - "node_modules/@types/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", - "dev": true - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", - "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/pug": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.10.tgz", - "integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==", - "dev": true - }, - "node_modules/@types/resolve": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", - "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dev": true, - "dependencies": { - "dequal": "^2.0.3" - } - }, - "node_modules/axobject-query": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", - "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", - "dev": true, - "dependencies": { - "dequal": "^2.0.3" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/code-red": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", - "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15", - "@types/estree": "^1.0.1", - "acorn": "^8.10.0", - "estree-walker": "^3.0.3", - "periscopic": "^3.1.0" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/detect-indent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/devalue": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.2.tgz", - "integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==", - "dev": true - }, - "node_modules/es6-promise": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", - "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", - "dev": true - }, - "node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" - } - }, - "node_modules/esm-env": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz", - "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==", - "dev": true - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globalyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", - "dev": true - }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/immutable": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", - "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", - "dev": true - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-meta-resolve": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz", - "integrity": "sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", - "dev": true, - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-reference": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", - "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", - "dev": true, - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/just-extend": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", - "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==" - }, - "node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/locate-character": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", - "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", - "dev": true - }, - "node_modules/magic-string": { - "version": "0.30.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz", - "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/mrmime": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", - "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/periscopic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", - "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^3.0.0", - "is-reference": "^3.0.0" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/rollup": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.3.tgz", - "integrity": "sha512-ag5tTQKYsj1bhrFC9+OEWqb5O6VYgtQDO9hPDBMmIbePwhfSr+ExlcU741t8Dhw5DkPCQf6noz0jb36D6W9/hw==", - "dev": true, - "dependencies": { - "@types/estree": "1.0.5" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.14.3", - "@rollup/rollup-android-arm64": "4.14.3", - "@rollup/rollup-darwin-arm64": "4.14.3", - "@rollup/rollup-darwin-x64": "4.14.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.14.3", - "@rollup/rollup-linux-arm-musleabihf": "4.14.3", - "@rollup/rollup-linux-arm64-gnu": "4.14.3", - "@rollup/rollup-linux-arm64-musl": "4.14.3", - "@rollup/rollup-linux-powerpc64le-gnu": "4.14.3", - "@rollup/rollup-linux-riscv64-gnu": "4.14.3", - "@rollup/rollup-linux-s390x-gnu": "4.14.3", - "@rollup/rollup-linux-x64-gnu": "4.14.3", - "@rollup/rollup-linux-x64-musl": "4.14.3", - "@rollup/rollup-win32-arm64-msvc": "4.14.3", - "@rollup/rollup-win32-ia32-msvc": "4.14.3", - "@rollup/rollup-win32-x64-msvc": "4.14.3", - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-svelte": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-svelte/-/rollup-plugin-svelte-7.2.0.tgz", - "integrity": "sha512-Qvo5VNFQZtaI+sHSjcCIFDP+olfKVyslAoJIkL3DxuhUpNY5Ys0+hhxUY3kuEKt9BXFgkFJiiic/XRb07zdSbg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^4.1.0", - "resolve.exports": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "rollup": ">=2.0.0", - "svelte": ">=3.5.0" - } - }, - "node_modules/rollup-plugin-svelte/node_modules/@rollup/pluginutils": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", - "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", - "dev": true, - "dependencies": { - "estree-walker": "^2.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/rollup-plugin-svelte/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/sade": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", - "dev": true, - "dependencies": { - "mri": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/sander": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", - "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", - "dev": true, - "dependencies": { - "es6-promise": "^3.1.2", - "graceful-fs": "^4.1.3", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.2" - } - }, - "node_modules/sass": { - "version": "1.74.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.74.1.tgz", - "integrity": "sha512-w0Z9p/rWZWelb88ISOLyvqTWGmtmu2QJICqDBGyNnfG4OUnPX9BBjjYIXUpXCMOOg5MQWNpqzt876la1fsTvUA==", - "dev": true, - "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/set-cookie-parser": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", - "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==", - "dev": true - }, - "node_modules/sirv": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", - "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", - "dev": true, - "dependencies": { - "@polka/url": "^1.0.0-next.24", - "mrmime": "^2.0.0", - "totalist": "^3.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/sorcery": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz", - "integrity": "sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.14", - "buffer-crc32": "^0.2.5", - "minimist": "^1.2.0", - "sander": "^0.5.0" - }, - "bin": { - "sorcery": "bin/sorcery" - } - }, - "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svelte": { - "version": "4.2.19", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz", - "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.1", - "@jridgewell/sourcemap-codec": "^1.4.15", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/estree": "^1.0.1", - "acorn": "^8.9.0", - "aria-query": "^5.3.0", - "axobject-query": "^4.0.0", - "code-red": "^1.0.3", - "css-tree": "^2.3.1", - "estree-walker": "^3.0.3", - "is-reference": "^3.0.1", - "locate-character": "^3.0.0", - "magic-string": "^0.30.4", - "periscopic": "^3.1.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/svelte-check": { - "version": "3.6.9", - "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.6.9.tgz", - "integrity": "sha512-hDQrk3L0osX07djQyMiXocKysTLfusqi8AriNcCiQxhQR49/LonYolcUGMtZ0fbUR8HTR198Prrgf52WWU9wEg==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", - "chokidar": "^3.4.1", - "fast-glob": "^3.2.7", - "import-fresh": "^3.2.1", - "picocolors": "^1.0.0", - "sade": "^1.7.4", - "svelte-preprocess": "^5.1.3", - "typescript": "^5.0.3" - }, - "bin": { - "svelte-check": "bin/svelte-check" - }, - "peerDependencies": { - "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0" - } - }, - "node_modules/svelte-hmr": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", - "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", - "dev": true, - "engines": { - "node": "^12.20 || ^14.13.1 || >= 16" - }, - "peerDependencies": { - "svelte": "^3.19.0 || ^4.0.0" - } - }, - "node_modules/svelte-preprocess": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.3.tgz", - "integrity": "sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@types/pug": "^2.0.6", - "detect-indent": "^6.1.0", - "magic-string": "^0.30.5", - "sorcery": "^0.11.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">= 16.0.0", - "pnpm": "^8.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.10.2", - "coffeescript": "^2.5.1", - "less": "^3.11.3 || ^4.0.0", - "postcss": "^7 || ^8", - "postcss-load-config": "^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", - "pug": "^3.0.0", - "sass": "^1.26.8", - "stylus": "^0.55.0", - "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", - "svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0", - "typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "coffeescript": { - "optional": true - }, - "less": { - "optional": true - }, - "postcss": { - "optional": true - }, - "postcss-load-config": { - "optional": true - }, - "pug": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/tiny-glob": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", - "dev": true, - "dependencies": { - "globalyzer": "0.1.0", - "globrex": "^0.1.2" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, - "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/vite": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz", - "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==", - "dev": true, - "dependencies": { - "esbuild": "^0.20.1", - "postcss": "^8.4.38", - "rollup": "^4.13.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vitefu": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", - "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", - "dev": true, - "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "vite": { - "optional": true - } - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - } - } + "name": "pastebook", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "pastebook", + "version": "0.0.1", + "dependencies": { + "just-extend": "^6.2.0" + }, + "devDependencies": { + "@fontsource/fira-mono": "^4.5.10", + "@neoconfetti/svelte": "^1.0.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "@sveltejs/adapter-auto": "^3.0.0", + "@sveltejs/adapter-node": "^5.0.1", + "@sveltejs/adapter-static": "^3.0.1", + "@sveltejs/kit": "^2.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "@types/node": "^20.12.7", + "prettier": "^3.3.3", + "prettier-plugin-svelte": "^3.2.7", + "rollup": "^4.14.3", + "rollup-plugin-svelte": "^7.2.0", + "sass": "^1.74.1", + "svelte": "^4.2.19", + "svelte-check": "^3.6.0", + "tslib": "^2.4.1", + "typescript": "^5.0.0", + "vite": "^5.0.3" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@fontsource/fira-mono": { + "version": "4.5.10", + "resolved": "https://registry.npmjs.org/@fontsource/fira-mono/-/fira-mono-4.5.10.tgz", + "integrity": "sha512-bxUnRP8xptGRo8YXeY073DSpfK74XpSb0ZyRNpHV9WvLnJ7TwPOjZll8hTMin7zLC6iOp59pDZ8EQDj1gzgAQQ==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@neoconfetti/svelte": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@neoconfetti/svelte/-/svelte-1.0.0.tgz", + "integrity": "sha512-SmksyaJAdSlMa9cTidVSIqYo1qti+WTsviNDwgjNVm+KQ3DRP2Df9umDIzC4vCcpEYY+chQe0i2IKnLw03AT8Q==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.25", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz", + "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==", + "dev": true + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "25.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz", + "integrity": "sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "node_modules/@rollup/plugin-commonjs/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.2.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", + "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.3.tgz", + "integrity": "sha512-X9alQ3XM6I9IlSlmC8ddAvMSyG1WuHk5oUnXGw+yUBs3BFoTizmG1La/Gr8fVJvDWAq+zlYTZ9DBgrlKRVY06g==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.3.tgz", + "integrity": "sha512-eQK5JIi+POhFpzk+LnjKIy4Ks+pwJ+NXmPxOCSvOKSNRPONzKuUvWE+P9JxGZVxrtzm6BAYMaL50FFuPe0oWMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.3.tgz", + "integrity": "sha512-Od4vE6f6CTT53yM1jgcLqNfItTsLt5zE46fdPaEmeFHvPs5SjZYlLpHrSiHEKR1+HdRfxuzXHjDOIxQyC3ptBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.3.tgz", + "integrity": "sha512-0IMAO21axJeNIrvS9lSe/PGthc8ZUS+zC53O0VhF5gMxfmcKAP4ESkKOCwEi6u2asUrt4mQv2rjY8QseIEb1aw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.3.tgz", + "integrity": "sha512-ge2DC7tHRHa3caVEoSbPRJpq7azhG+xYsd6u2MEnJ6XzPSzQsTKyXvh6iWjXRf7Rt9ykIUWHtl0Uz3T6yXPpKw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.14.3.tgz", + "integrity": "sha512-ljcuiDI4V3ySuc7eSk4lQ9wU8J8r8KrOUvB2U+TtK0TiW6OFDmJ+DdIjjwZHIw9CNxzbmXY39wwpzYuFDwNXuw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.3.tgz", + "integrity": "sha512-Eci2us9VTHm1eSyn5/eEpaC7eP/mp5n46gTRB3Aar3BgSvDQGJZuicyq6TsH4HngNBgVqC5sDYxOzTExSU+NjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.3.tgz", + "integrity": "sha512-UrBoMLCq4E92/LCqlh+blpqMz5h1tJttPIniwUgOFJyjWI1qrtrDhhpHPuFxULlUmjFHfloWdixtDhSxJt5iKw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.3.tgz", + "integrity": "sha512-5aRjvsS8q1nWN8AoRfrq5+9IflC3P1leMoy4r2WjXyFqf3qcqsxRCfxtZIV58tCxd+Yv7WELPcO9mY9aeQyAmw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.3.tgz", + "integrity": "sha512-sk/Qh1j2/RJSX7FhEpJn8n0ndxy/uf0kI/9Zc4b1ELhqULVdTfN6HL31CDaTChiBAOgLcsJ1sgVZjWv8XNEsAQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.3.tgz", + "integrity": "sha512-jOO/PEaDitOmY9TgkxF/TQIjXySQe5KVYB57H/8LRP/ux0ZoO8cSHCX17asMSv3ruwslXW/TLBcxyaUzGRHcqg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.3.tgz", + "integrity": "sha512-8ybV4Xjy59xLMyWo3GCfEGqtKV5M5gCSrZlxkPGvEPCGDLNla7v48S662HSGwRd6/2cSneMQWiv+QzcttLrrOA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.3.tgz", + "integrity": "sha512-s+xf1I46trOY10OqAtZ5Rm6lzHre/UiLA1J2uOhCFXWkbZrJRkYBPO6FhvGfHmdtQ3Bx793MNa7LvoWFAm93bg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.3.tgz", + "integrity": "sha512-+4h2WrGOYsOumDQ5S2sYNyhVfrue+9tc9XcLWLh+Kw3UOxAvrfOrSMFon60KspcDdytkNDh7K2Vs6eMaYImAZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.3.tgz", + "integrity": "sha512-T1l7y/bCeL/kUwh9OD4PQT4aM7Bq43vX05htPJJ46RTI4r5KNt6qJRzAfNfM+OYMNEVBWQzR2Gyk+FXLZfogGw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.3.tgz", + "integrity": "sha512-/BypzV0H1y1HzgYpxqRaXGBRqfodgoBBCcsrujT6QRcakDQdfU+Lq9PENPh5jB4I44YWq+0C2eHsHya+nZY1sA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sveltejs/adapter-auto": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-3.2.0.tgz", + "integrity": "sha512-She5nKT47kwHE18v9NMe6pbJcvULr82u0V3yZ0ej3n1laWKGgkgdEABE9/ak5iDPs93LqsBkuIo51kkwCLBjJA==", + "dev": true, + "dependencies": { + "import-meta-resolve": "^4.0.0" + }, + "peerDependencies": { + "@sveltejs/kit": "^2.0.0" + } + }, + "node_modules/@sveltejs/adapter-node": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.0.1.tgz", + "integrity": "sha512-eYdmxdUWMW+dad1JfMsWBPY2vjXz9eE+52A2AQnXPScPJlIxIVk5mmbaEEzrZivLfO2wEcLTZ5vdC03W69x+iA==", + "dev": true, + "dependencies": { + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "rollup": "^4.9.5" + }, + "peerDependencies": { + "@sveltejs/kit": "^2.4.0" + } + }, + "node_modules/@sveltejs/adapter-static": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.1.tgz", + "integrity": "sha512-6lMvf7xYEJ+oGeR5L8DFJJrowkefTK6ZgA4JiMqoClMkKq0s6yvsd3FZfCFvX1fQ0tpCD7fkuRVHsnUVgsHyNg==", + "dev": true, + "peerDependencies": { + "@sveltejs/kit": "^2.0.0" + } + }, + "node_modules/@sveltejs/kit": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.5.tgz", + "integrity": "sha512-ULe3PB00q4+wYRL+IS5FDPsCEVnhEITofm7b9Yz8malcH3r1SAnW/JJ6T13hIMeu8QNRIuVQWo+P4+2VklbnLQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^0.6.0", + "devalue": "^4.3.2", + "esm-env": "^1.0.0", + "import-meta-resolve": "^4.0.0", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "sade": "^1.8.1", + "set-cookie-parser": "^2.6.0", + "sirv": "^2.0.4", + "tiny-glob": "^0.2.9" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "engines": { + "node": ">=18.13" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.3" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.0.tgz", + "integrity": "sha512-sY6ncCvg+O3njnzbZexcVtUqOBE3iYmQPJ9y+yXSkOwG576QI/xJrBnQSRXFLGwJNBa0T78JEKg5cIR0WOAuUw==", + "dev": true, + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^2.0.0", + "debug": "^4.3.4", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.9", + "svelte-hmr": "^0.16.0", + "vitefu": "^0.2.5" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.1.0.tgz", + "integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/pug": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.10.tgz", + "integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==", + "dev": true + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/axobject-query": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", + "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/code-red": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", + "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.1", + "acorn": "^8.10.0", + "estree-walker": "^3.0.3", + "periscopic": "^3.1.0" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.2.tgz", + "integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==", + "dev": true + }, + "node_modules/es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/esm-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz", + "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==", + "dev": true + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globalyzer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", + "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", + "dev": true + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz", + "integrity": "sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/just-extend": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", + "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==" + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dev": true + }, + "node_modules/magic-string": { + "version": "0.30.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz", + "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-svelte": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.2.7.tgz", + "integrity": "sha512-/Dswx/ea0lV34If1eDcG3nulQ63YNr5KPDfMsjbdtpSWOxKKJ7nAc2qlVuYwEvCr4raIuredNoR7K4JCkmTGaQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "prettier": "^3.0.0", + "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rollup": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.3.tgz", + "integrity": "sha512-ag5tTQKYsj1bhrFC9+OEWqb5O6VYgtQDO9hPDBMmIbePwhfSr+ExlcU741t8Dhw5DkPCQf6noz0jb36D6W9/hw==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.14.3", + "@rollup/rollup-android-arm64": "4.14.3", + "@rollup/rollup-darwin-arm64": "4.14.3", + "@rollup/rollup-darwin-x64": "4.14.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.14.3", + "@rollup/rollup-linux-arm-musleabihf": "4.14.3", + "@rollup/rollup-linux-arm64-gnu": "4.14.3", + "@rollup/rollup-linux-arm64-musl": "4.14.3", + "@rollup/rollup-linux-powerpc64le-gnu": "4.14.3", + "@rollup/rollup-linux-riscv64-gnu": "4.14.3", + "@rollup/rollup-linux-s390x-gnu": "4.14.3", + "@rollup/rollup-linux-x64-gnu": "4.14.3", + "@rollup/rollup-linux-x64-musl": "4.14.3", + "@rollup/rollup-win32-arm64-msvc": "4.14.3", + "@rollup/rollup-win32-ia32-msvc": "4.14.3", + "@rollup/rollup-win32-x64-msvc": "4.14.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-svelte": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-svelte/-/rollup-plugin-svelte-7.2.0.tgz", + "integrity": "sha512-Qvo5VNFQZtaI+sHSjcCIFDP+olfKVyslAoJIkL3DxuhUpNY5Ys0+hhxUY3kuEKt9BXFgkFJiiic/XRb07zdSbg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^4.1.0", + "resolve.exports": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "rollup": ">=2.0.0", + "svelte": ">=3.5.0" + } + }, + "node_modules/rollup-plugin-svelte/node_modules/@rollup/pluginutils": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", + "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", + "dev": true, + "dependencies": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/rollup-plugin-svelte/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/sander": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", + "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", + "dev": true, + "dependencies": { + "es6-promise": "^3.1.2", + "graceful-fs": "^4.1.3", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.2" + } + }, + "node_modules/sass": { + "version": "1.74.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.74.1.tgz", + "integrity": "sha512-w0Z9p/rWZWelb88ISOLyvqTWGmtmu2QJICqDBGyNnfG4OUnPX9BBjjYIXUpXCMOOg5MQWNpqzt876la1fsTvUA==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==", + "dev": true + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sorcery": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz", + "integrity": "sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.14", + "buffer-crc32": "^0.2.5", + "minimist": "^1.2.0", + "sander": "^0.5.0" + }, + "bin": { + "sorcery": "bin/sorcery" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svelte": { + "version": "4.2.19", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz", + "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.1", + "@jridgewell/sourcemap-codec": "^1.4.15", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/estree": "^1.0.1", + "acorn": "^8.9.0", + "aria-query": "^5.3.0", + "axobject-query": "^4.0.0", + "code-red": "^1.0.3", + "css-tree": "^2.3.1", + "estree-walker": "^3.0.3", + "is-reference": "^3.0.1", + "locate-character": "^3.0.0", + "magic-string": "^0.30.4", + "periscopic": "^3.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/svelte-check": { + "version": "3.6.9", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.6.9.tgz", + "integrity": "sha512-hDQrk3L0osX07djQyMiXocKysTLfusqi8AriNcCiQxhQR49/LonYolcUGMtZ0fbUR8HTR198Prrgf52WWU9wEg==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "chokidar": "^3.4.1", + "fast-glob": "^3.2.7", + "import-fresh": "^3.2.1", + "picocolors": "^1.0.0", + "sade": "^1.7.4", + "svelte-preprocess": "^5.1.3", + "typescript": "^5.0.3" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "peerDependencies": { + "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0" + } + }, + "node_modules/svelte-hmr": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", + "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", + "dev": true, + "engines": { + "node": "^12.20 || ^14.13.1 || >= 16" + }, + "peerDependencies": { + "svelte": "^3.19.0 || ^4.0.0" + } + }, + "node_modules/svelte-preprocess": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.3.tgz", + "integrity": "sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/pug": "^2.0.6", + "detect-indent": "^6.1.0", + "magic-string": "^0.30.5", + "sorcery": "^0.11.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">= 16.0.0", + "pnpm": "^8.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.10.2", + "coffeescript": "^2.5.1", + "less": "^3.11.3 || ^4.0.0", + "postcss": "^7 || ^8", + "postcss-load-config": "^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", + "pug": "^3.0.0", + "sass": "^1.26.8", + "stylus": "^0.55.0", + "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0", + "typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "coffeescript": { + "optional": true + }, + "less": { + "optional": true + }, + "postcss": { + "optional": true + }, + "postcss-load-config": { + "optional": true + }, + "pug": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/tiny-glob": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", + "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "dev": true, + "dependencies": { + "globalyzer": "0.1.0", + "globrex": "^0.1.2" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/vite": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz", + "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==", + "dev": true, + "dependencies": { + "esbuild": "^0.20.1", + "postcss": "^8.4.38", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", + "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "dev": true, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + } + } } diff --git a/website/pastebook/package.json b/website/pastebook/package.json index d171238..b9ca98f 100644 --- a/website/pastebook/package.json +++ b/website/pastebook/package.json @@ -1,34 +1,36 @@ { - "name": "pastebook", - "version": "0.0.1", - "scripts": { - "dev": "vite dev", - "build": "vite build", - "preview": "vite preview", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" - }, - "devDependencies": { - "@fontsource/fira-mono": "^4.5.10", - "@neoconfetti/svelte": "^1.0.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@sveltejs/adapter-auto": "^3.0.0", - "@sveltejs/adapter-node": "^5.0.1", - "@sveltejs/adapter-static": "^3.0.1", - "@sveltejs/kit": "^2.0.0", - "@sveltejs/vite-plugin-svelte": "^3.0.0", - "@types/node": "^20.12.7", - "rollup": "^4.14.3", - "rollup-plugin-svelte": "^7.2.0", - "sass": "^1.74.1", - "svelte": "^4.2.19", - "svelte-check": "^3.6.0", - "tslib": "^2.4.1", - "typescript": "^5.0.0", - "vite": "^5.0.3" - }, - "type": "module", - "dependencies": { - "just-extend": "^6.2.0" - } + "name": "pastebook", + "version": "0.0.1", + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" + }, + "devDependencies": { + "@fontsource/fira-mono": "^4.5.10", + "@neoconfetti/svelte": "^1.0.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "@sveltejs/adapter-auto": "^3.0.0", + "@sveltejs/adapter-node": "^5.0.1", + "@sveltejs/adapter-static": "^3.0.1", + "@sveltejs/kit": "^2.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "@types/node": "^20.12.7", + "prettier": "^3.3.3", + "prettier-plugin-svelte": "^3.2.7", + "rollup": "^4.14.3", + "rollup-plugin-svelte": "^7.2.0", + "sass": "^1.74.1", + "svelte": "^4.2.19", + "svelte-check": "^3.6.0", + "tslib": "^2.4.1", + "typescript": "^5.0.0", + "vite": "^5.0.3" + }, + "type": "module", + "dependencies": { + "just-extend": "^6.2.0" + } } diff --git a/website/pastebook/src/app.d.ts b/website/pastebook/src/app.d.ts index 9898818..61f504e 100755 --- a/website/pastebook/src/app.d.ts +++ b/website/pastebook/src/app.d.ts @@ -1,8 +1,7 @@ // See https://kit.svelte.dev/docs/types#app // for information about these interfaces declare global { - namespace App { - } + namespace App {} } export {}; diff --git a/website/pastebook/src/app.html b/website/pastebook/src/app.html index 3c399dd..9a8ca3c 100755 --- a/website/pastebook/src/app.html +++ b/website/pastebook/src/app.html @@ -1,36 +1,46 @@ - - - - - - - - - PasteBook - - %sveltekit.head% - - -
%sveltekit.body%
- + + + + + + + + + PasteBook + + %sveltekit.head% + + +
%sveltekit.body%
+ \ No newline at end of file + if (localStorage.getItem("dark-mode") == null) { + if (window.matchMedia("(prefers-color-scheme: dark)").matches) { + document.querySelector("body").classList.add("dark-mode"); + } else { + document.querySelector("body").classList.remove("dark-mode"); + } + } + diff --git a/website/pastebook/src/components/Beta.svelte b/website/pastebook/src/components/Beta.svelte index dade635..95278c2 100755 --- a/website/pastebook/src/components/Beta.svelte +++ b/website/pastebook/src/components/Beta.svelte @@ -1,30 +1,32 @@ -BETA +BETA \ No newline at end of file + .beta:hover { + cursor: pointer; + transform: translateY(10%); + } + diff --git a/website/pastebook/src/components/Content.svelte b/website/pastebook/src/components/Content.svelte index 911566f..e048e0f 100755 --- a/website/pastebook/src/components/Content.svelte +++ b/website/pastebook/src/components/Content.svelte @@ -1,253 +1,261 @@ - {#if !newReport} -
- - {#each contentLines as line, index} - {getIndex(index + 1)}{line} - {/each} - -
- {:else} - {/if}
@@ -269,11 +270,6 @@ overflow-x: scroll; border: 1px solid #c9c9c9; - @media (max-width: 600px) { - height: calc(100% - 130px); - margin-top: 6px; - } - :global(.dark-mode) & { border: 1px solid #333; background-color: #1a1a1a; @@ -284,6 +280,11 @@ } transition: all 0.5s ease; + + @media (max-width: 600px) { + height: calc(100% - 130px); + margin-top: 6px; + } } .input { @@ -341,11 +342,6 @@ background-color: orange; } - @media (max-width: 600px) { - font-size: 10px; - padding-right: 12px; - } - .dark-mode & { color: #999; } @@ -353,6 +349,11 @@ transition: all 0.2s ease, font-weight 0.5s ease; + + @media (max-width: 600px) { + font-size: 10px; + padding-right: 12px; + } } linecontainer { @@ -372,19 +373,18 @@ white-space: break-spaces; } + :global(body.dark-mode) & { + color: white; + } + @media (max-width: 600px) { font-size: 10px; padding-left: 30px; text-indent: -18px; } - - :global(body.dark-mode) & { - color: white; - } } line-content-container { - // margin-right: 30px;t &.severity-1 { background-color: rgb(255, 165, 0, 0.7); } diff --git a/frontend/src/components/Header.svelte b/frontend/src/components/Header.svelte index b2c5407..e7b17f9 100755 --- a/frontend/src/components/Header.svelte +++ b/frontend/src/components/Header.svelte @@ -73,12 +73,11 @@ animation: fadeIn ease 0.7s; animation-iteration-count: 1; animation-fill-mode: forwards; + transition: color 0.2s ease; :global(.dark-mode) & { color: white; } - - transition: color 0.2s ease; } created { @@ -99,11 +98,11 @@ animation-iteration-count: 1; animation-fill-mode: forwards; + transition: color 0.2s ease; + :global(.dark-mode) & { color: lightgray; } - - transition: color 0.2s ease; } @keyframes fadeIn { diff --git a/frontend/src/components/Highlight.svelte b/frontend/src/components/Highlight.svelte index f80f520..1c43725 100755 --- a/frontend/src/components/Highlight.svelte +++ b/frontend/src/components/Highlight.svelte @@ -91,11 +91,6 @@ margin: 0; right: 100px; - @media (max-width: 600px) { - left: 30px; - right: unset; - } - bottom: 0; background: #ffcc00; @@ -119,6 +114,11 @@ cursor: pointer; bottom: -2px; } + + @media (max-width: 600px) { + left: 30px; + right: unset; + } } } diff --git a/frontend/src/components/PotentialIssues.svelte b/frontend/src/components/PotentialIssues.svelte index 90b2d53..5b97070 100755 --- a/frontend/src/components/PotentialIssues.svelte +++ b/frontend/src/components/PotentialIssues.svelte @@ -72,11 +72,11 @@ "JetBrains Mono", monospace; + display: inline-block; + @media (max-width: 800px) { font-size: 1em; } - - display: inline-block; } .severe, @@ -90,10 +90,6 @@ color: black; opacity: 0; - @media (max-width: 800px) { - font-size: 0.8em; - } - animation: fadeIn 0.5s ease-in-out forwards; animation-delay: 0.1s; @@ -109,6 +105,10 @@ white-space: nowrap; overflow: scroll; padding: 10px 20px 10px 10px; + + @media (max-width: 800px) { + font-size: 0.8em; + } } .severe { diff --git a/frontend/src/components/Toolbar.svelte b/frontend/src/components/Toolbar.svelte index 876b7e2..9feeb82 100755 --- a/frontend/src/components/Toolbar.svelte +++ b/frontend/src/components/Toolbar.svelte @@ -48,70 +48,75 @@ background-color: #eeeeee; opacity: 0; - @media (max-width: 600px) { - height: 20px; - } - + display: flex; justify-content: space-between; - + color: gray; border: 1px solid #c9c9c9; - + :global(.dark-mode) & { border: 1px solid #333; background-color: #1a1a1a; } - + &:active { transform: scale(0.95); } - + button { transition: - opacity 0.7s, - transform 0.5s, - color 0.5s; + opacity 0.7s, + transform 0.5s, + color 0.5s; align-self: center; - + font-size: 1rem; font-weight: 700; margin: 0; font-family: Gabarito, sans-serif; border: none; color: gray; - + padding-left: 20px; padding-right: 30px; background-color: transparent; outline: none; - + &:hover { color: darkgray; cursor: pointer; } - + &:active { transform: scale(0.95); } - + @media (max-width: 600px) { font-size: 0.6rem; padding: 0 0 0 20px; } } - + buttons { display: flex; - + @media (max-width: 600px) { font-size: 0.6rem; - padding-right: 30px; + padding-right: 20px; } } + + @media (max-width: 600px) { + height: 20px; + } } #main { padding-left: 30px; + + @media (max-width: 600px) { + padding-left: 20px; + } } diff --git a/frontend/src/components/pulltab/Pulltab.svelte b/frontend/src/components/pulltab/Pulltab.svelte index 06c0bc5..dc4c2ca 100755 --- a/frontend/src/components/pulltab/Pulltab.svelte +++ b/frontend/src/components/pulltab/Pulltab.svelte @@ -49,10 +49,10 @@ - + - + diff --git a/frontend/src/components/settings/Setting.svelte b/frontend/src/components/settings/Setting.svelte index c92486f..12fb350 100755 --- a/frontend/src/components/settings/Setting.svelte +++ b/frontend/src/components/settings/Setting.svelte @@ -39,13 +39,13 @@ color: black; font-family: Gabarito, sans-serif; - @media (max-width: 768px) { - font-size: 1em; - } - :global(.dark-mode) & { color: white; } + + @media (max-width: 768px) { + font-size: 1em; + } } settingdescription { diff --git a/frontend/src/components/settings/Switch.svelte b/frontend/src/components/settings/Switch.svelte index f73c26d..4d64508 100755 --- a/frontend/src/components/settings/Switch.svelte +++ b/frontend/src/components/settings/Switch.svelte @@ -34,6 +34,7 @@ bind:this={background} class="container bg-active-{isSelected}" on:click={toggleSelected} + aria-label="Toggle" > @@ -61,14 +62,14 @@ border: 1px solid #333; } + :active & { + transform: scale(0.96); + } + @media (max-width: 600px) { width: 40px; height: 25px; } - - :active & { - transform: scale(0.96); - } } :global(.bg-active-true) { @@ -96,16 +97,16 @@ border-radius: 50%; background-color: dimgray; - @media (max-width: 600px) { - height: 20px; - width: 20px; - } - :global(.dark-mode) & { background-color: white; } padding: 0; + + @media (max-width: 600px) { + height: 20px; + width: 20px; + } } .active-false { diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index 486bc31..d7a006e 100755 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -1,39 +1,25 @@ - - - -

PasteBook

-

By Loudbook

-

- PasteBook is an aesthetic, effortless way to share your blocks of text, and - respects your privacy by automatically deleting your pastes. -

- - {#if width > 768} - - - GITHUB - - CONTACT - - PRIVACY - {:else} -
- -
+ + window.onresize = () => { + width = window.innerWidth; + }; + }); + + + +

PasteBook

+

+ PasteBook is an aesthetic, effortless way to share your blocks of text, and + respects your privacy by automatically deleting your pastes. +

+ - {/if} - - - -
- - - - - - + diff --git a/frontend/src/routes/[pastes=paste]/[slug]/+page.svelte b/frontend/src/routes/[pastes=paste]/[slug]/+page.svelte index 850833d..c4c9356 100755 --- a/frontend/src/routes/[pastes=paste]/[slug]/+page.svelte +++ b/frontend/src/routes/[pastes=paste]/[slug]/+page.svelte @@ -195,12 +195,12 @@ font-family: Gabarito, sans-serif; text-align: center; - @media (max-width: 600px) { - font-size: 10px; - } - &.extra-padding-true { padding: 0 0 40px; } + + @media (max-width: 600px) { + font-size: 10px; + } } diff --git a/frontend/src/routes/privacy/+page.svelte b/frontend/src/routes/privacy/+page.svelte index 151a780..168f916 100755 --- a/frontend/src/routes/privacy/+page.svelte +++ b/frontend/src/routes/privacy/+page.svelte @@ -1101,11 +1101,6 @@ overflow-x: scroll; outline: 1px solid #c9c9c9; - @media (max-width: 600px) { - height: calc(100% - 130px); - margin-top: 6px; - } - :global(.dark-mode) & { outline: 1px solid #333; background-color: #1a1a1a; @@ -1123,6 +1118,11 @@ opacity: 1; } } + + @media (max-width: 600px) { + height: calc(100% - 130px); + margin-top: 6px; + } } #inner-content { @@ -1135,13 +1135,13 @@ transition: color 0.5s ease; font-size: 12px; - @media (max-width: 600px) { - font-size: 10px; - } - :global(.dark-mode) & { color: white; } + + @media (max-width: 600px) { + font-size: 10px; + } } a { @@ -1169,12 +1169,12 @@ color: black; transition: color 0.5s ease; - @media (max-width: 600px) { - font-size: 10px; - } - :global(.dark-mode) & { color: white; } + + @media (max-width: 600px) { + font-size: 10px; + } } diff --git a/frontend/src/routes/settings/+page.svelte b/frontend/src/routes/settings/+page.svelte index 3e60dbe..9db16e5 100755 --- a/frontend/src/routes/settings/+page.svelte +++ b/frontend/src/routes/settings/+page.svelte @@ -161,17 +161,17 @@ padding: 10px 10px 5px; opacity: 0; - @media (max-width: 600px) { - height: calc(100% - 130px); - margin-top: 6px; - } - :global(.dark-mode) & { border: 1px solid #333; background-color: #1a1a1a; } animation: fadeIn 0.5s forwards; + + @media (max-width: 600px) { + height: calc(100% - 130px); + margin-top: 6px; + } } #padding { diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 80864b9..766662e 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -3,4 +3,11 @@ import { defineConfig } from "vite"; export default defineConfig({ plugins: [sveltekit()], -}); + css: { + preprocessorOptions: { + scss: { + api: 'modern-compiler' + } + } + } +}); \ No newline at end of file From 00416433b268da2eb9c855fa4b97efde9d2ba8c5 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Wed, 4 Dec 2024 19:10:20 -0500 Subject: [PATCH 081/188] Fix potential logging conflict --- backend/build.gradle.kts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts index 2bf2fb4..1879de3 100644 --- a/backend/build.gradle.kts +++ b/backend/build.gradle.kts @@ -54,3 +54,7 @@ tasks.bootJar { tasks.withType { useJUnitPlatform() } + +configurations.implementation { + exclude(group = "commons-logging", module = "commons-logging") +} \ No newline at end of file From 007d28d3efb8170cad9c279373f4523d9626480b Mon Sep 17 00:00:00 2001 From: Loudbook Date: Wed, 4 Dec 2024 19:34:41 -0500 Subject: [PATCH 082/188] Update Java & Kotlin --- backend/Dockerfile | 2 +- backend/build.gradle.kts | 20 ++++++++++--------- .../gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 660518c..86a4f1b 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,5 +1,5 @@ -FROM openjdk:21-jdk-slim +FROM openjdk:23-slim WORKDIR /pastebook-backend diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts index 1879de3..4ad82b5 100644 --- a/backend/build.gradle.kts +++ b/backend/build.gradle.kts @@ -1,10 +1,11 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - id("org.springframework.boot") version "3.2.4" - id("io.spring.dependency-management") version "1.1.4" - kotlin("jvm") version "1.9.23" - kotlin("plugin.spring") version "1.9.23" + id("org.springframework.boot") version "3.4.0" + id("io.spring.dependency-management") version "1.1.6" + kotlin("jvm") version "2.1.0" + kotlin("plugin.spring") version "2.1.0" } val springCloudVersion by extra("2023.0.1") @@ -12,7 +13,8 @@ group = "dev.loudbook" version = "0.0.1-SNAPSHOT" java { - sourceCompatibility = JavaVersion.VERSION_21 + sourceCompatibility = JavaVersion.VERSION_23 + targetCompatibility = JavaVersion.VERSION_23 } repositories { @@ -26,7 +28,7 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("com.github.vladimir-bukhtoyarov:bucket4j-core:8.0.1") testImplementation("org.springframework.boot:spring-boot-starter-test") - implementation("com.google.code.gson:gson:2.10.1") + implementation("com.google.code.gson:gson:2.11.0") implementation("me.paulschwarz:spring-dotenv:4.0.0") implementation("commons-validator:commons-validator:1.8.0") implementation("com.amazonaws:aws-java-sdk-s3:1.12.717") @@ -39,9 +41,9 @@ dependencyManagement { } tasks.withType { - kotlinOptions { - freeCompilerArgs += "-Xjsr305=strict" - jvmTarget = "21" + compilerOptions { + freeCompilerArgs.add("-Xjsr305=strict") + jvmTarget.set(JvmTarget.JVM_23) } } diff --git a/backend/gradle/wrapper/gradle-wrapper.properties b/backend/gradle/wrapper/gradle-wrapper.properties index df97d72..e2847c8 100644 --- a/backend/gradle/wrapper/gradle-wrapper.properties +++ b/backend/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 798b4cb94ee563793f5faf64ed698fe555c34bf3 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Wed, 4 Dec 2024 19:35:00 -0500 Subject: [PATCH 083/188] Update build-and-deploy.yml --- .github/workflows/build-and-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 3e51754..5b73178 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -21,7 +21,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: temurin - java-version: 21 + java-version: 23 - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 From e07f130a5af824570276281d755396d1ccd54ef9 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Wed, 4 Dec 2024 23:36:08 -0500 Subject: [PATCH 084/188] Seperate content and metadata requests --- frontend/src/routes/[pastes=paste]/[slug]/+page.server.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend/src/routes/[pastes=paste]/[slug]/+page.server.ts b/frontend/src/routes/[pastes=paste]/[slug]/+page.server.ts index 9722db8..198c546 100755 --- a/frontend/src/routes/[pastes=paste]/[slug]/+page.server.ts +++ b/frontend/src/routes/[pastes=paste]/[slug]/+page.server.ts @@ -35,13 +35,11 @@ export async function load({ params, cookies }) { return { metadata: metadataPromise, - content: metadataPromise.then(async () => { - return fetch("http://backend:8080/get/" + path + "/content").then( + content: fetch("http://backend:8080/get/" + path + "/content").then( (response) => { return response.text(); }, - ); - }), + ), inspect: cookies.get("inspect") === "true", }; } From 50a1c04cb409da1ba764db14d1f0a2b6c7538d23 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 6 Dec 2024 12:03:02 -0500 Subject: [PATCH 085/188] Update build-and-deploy.yml --- .github/workflows/build-and-deploy.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 5b73178..53ece38 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -40,6 +40,10 @@ jobs: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + + - name: Get Commit Hash + id: get_commit_hash + run: echo "hash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV - name: Build and push frontend Docker image to GHCR uses: docker/build-push-action@v3 @@ -47,7 +51,9 @@ jobs: context: ./frontend file: ./frontend/Dockerfile push: true - tags: ghcr.io/loudbooks/pastebook-frontend:latest + tags: | + ghcr.io/loudbooks/pastebook-frontend:latest + ghcr.io/loudbooks/pastebook-frontend:${{ env.hash }} - name: Build and push backend Docker image to GHCR uses: docker/build-push-action@v3 @@ -55,7 +61,9 @@ jobs: context: ./backend file: ./backend/Dockerfile push: true - tags: ghcr.io/loudbooks/pastebook-backend:latest + tags: | + ghcr.io/loudbooks/pastebook-backend:latest + ghcr.io/loudbooks/pastebook-backend:${{ env.hash }} - name: Log in to Docker Hub uses: docker/login-action@v2 From 47bf7e15220a59fe03ac2f7c30df65508c6d862b Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 6 Dec 2024 12:12:02 -0500 Subject: [PATCH 086/188] Update build-and-deploy.yml --- .github/workflows/build-and-deploy.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 53ece38..3fa83e2 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -50,6 +50,8 @@ jobs: with: context: ./frontend file: ./frontend/Dockerfile + build-args: | + COMMIT_HASH=${{ env.hash }} push: true tags: | ghcr.io/loudbooks/pastebook-frontend:latest From 403dd2622f5f1f69ec12ad4d787d8dd9afd0f995 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 6 Dec 2024 12:24:30 -0500 Subject: [PATCH 087/188] Commit Hash --- frontend/Dockerfile | 3 + frontend/src/routes/+page.svelte | 94 ++++++++------------------------ 2 files changed, 25 insertions(+), 72 deletions(-) diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 7e7636c..1838134 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -15,6 +15,9 @@ COPY --from=build /pastebook-frontend /pastebook-frontend RUN npm install --production +ARG COMMIT_HASH +ENV VITE_COMMIT_HASH=$COMMIT_HASH + EXPOSE 3000 CMD ["node", "build"] \ No newline at end of file diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index d7a006e..2927103 100755 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -2,9 +2,12 @@ import Mode from "../components/Mode.svelte"; import { onMount } from "svelte"; + export const commitHash = import.meta.env.VITE_COMMIT_HASH || 'unknown'; + let width = 0; onMount(() => { + width = window.innerWidth; window.onresize = () => { @@ -19,20 +22,10 @@ PasteBook is an aesthetic, effortless way to share your blocks of text, and respects your privacy by automatically deleting your pastes.

- -
- GITHUB - - CONTACT - - PRIVACY -
-
- -
-
+ +
@@ -109,77 +102,35 @@ max-width: 400px; } } + } - buttons { - opacity: 0; - animation: fadeUp 1s var(--animation); - animation-delay: 0.3s; - animation-fill-mode: forwards; - } - - dot { - color: gray; - font-size: 20px; - margin: 0 10px; - transition: all 1s ease; - text-align: center; - - &:hover { - cursor: default; - } + .footer { + position: fixed; + bottom: 5px; + font-size: 11px; + font-family: "Jetbrains Mono", sans-serif; + color: gray; - &::selection { - background-color: transparent; - } + animation: fadeUp 1s var(--animation) forwards; + animation-delay: 0.4s; + opacity: 0; - @media (max-width: 768px) { - font-size: 13px; - margin: 0 5px; - } + @media (max-width: 768px) { + font-size: 8px; } - button, a { - display: inline-block; - appearance: none; - border: none; - padding: 10px 10px; - font-size: 20px; - background-color: transparent; color: gray; - cursor: pointer; - transition: all 0.5s; - font-family: Gabarito, sans-serif; text-decoration: none; font-weight: 600; &:hover { - color: darkgray; - cursor: pointer; - } - - &:active { - transform: scale(0.97); - } - - @media (max-width: 768px) { - font-size: 13px; - padding: 5px 0; - } - } - - #second-container { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - - a { - display: block; + text-decoration: underline; } } + } - @keyframes fadeUp { + @keyframes fadeUp { from { opacity: 0; transform: translateY(25px); @@ -189,5 +140,4 @@ transform: translateY(0); } } - } From 83e3b52be6719802872fcfd27ee63240f45a01bd Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 6 Dec 2024 12:33:16 -0500 Subject: [PATCH 088/188] Reorganize Dockerfile --- frontend/Dockerfile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 1838134..5bf26a1 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -2,6 +2,11 @@ FROM node:23-alpine AS build WORKDIR /pastebook-frontend +ARG COMMIT_HASH +ENV VITE_COMMIT_HASH=$COMMIT_HASH + +RUN echo "VITE_COMMIT_HASH=$VITE_COMMIT_HASH" >> .env + COPY package*.json ./ RUN npm install COPY . . @@ -15,9 +20,6 @@ COPY --from=build /pastebook-frontend /pastebook-frontend RUN npm install --production -ARG COMMIT_HASH -ENV VITE_COMMIT_HASH=$COMMIT_HASH - EXPOSE 3000 CMD ["node", "build"] \ No newline at end of file From 77d2f0a09f3f748eadb0dbed8ebba77b64e5c086 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 6 Dec 2024 12:40:43 -0500 Subject: [PATCH 089/188] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 32ab727..e97f64e 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Start by creating a file named `docker-compose.yml`. Add the content below. ```yml services: backend: - image: loudbook/pastebook-backend:latest + image: ghcr.io/loudbook/pastebook-backend:latest ports: - "8080:8080" environment: @@ -29,7 +29,7 @@ services: - pastebook-network frontend: - image: loudbook/pastebook-frontend:latest + image: ghcr.io/loudbook/pastebook-frontend:latest ports: - "3000:3000" depends_on: From a027f7489fa1d81f19926cc232552547f3ba0d83 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 6 Dec 2024 13:41:24 -0500 Subject: [PATCH 090/188] Customizable title and description --- frontend/src/components/Toolbar.svelte | 3 +- frontend/src/lib/stores.ts | 3 + frontend/src/routes/+layout.server.ts | 8 + frontend/src/routes/+layout.svelte | 10 +- frontend/src/routes/+page.svelte | 10 +- frontend/src/routes/privacy/+page.svelte | 1180 ---------------------- 6 files changed, 26 insertions(+), 1188 deletions(-) create mode 100644 frontend/src/routes/+layout.server.ts delete mode 100755 frontend/src/routes/privacy/+page.svelte diff --git a/frontend/src/components/Toolbar.svelte b/frontend/src/components/Toolbar.svelte index 9feeb82..4ad8e40 100755 --- a/frontend/src/components/Toolbar.svelte +++ b/frontend/src/components/Toolbar.svelte @@ -1,5 +1,6 @@ - + diff --git a/frontend/src/lib/stores.ts b/frontend/src/lib/stores.ts index 0900701..520ee7a 100755 --- a/frontend/src/lib/stores.ts +++ b/frontend/src/lib/stores.ts @@ -15,3 +15,6 @@ export const pasteURL = writable(""); export const wrap = writable(false); export const expire = writable(86400000); + +export const title = writable(""); +export const description = writable(""); \ No newline at end of file diff --git a/frontend/src/routes/+layout.server.ts b/frontend/src/routes/+layout.server.ts new file mode 100644 index 0000000..718fe83 --- /dev/null +++ b/frontend/src/routes/+layout.server.ts @@ -0,0 +1,8 @@ +import type { PageServerLoad } from './$types'; + +export const load: PageServerLoad = async ({ params }) => { + return { + title: process.env.TITLE, + description: process.env.DESCRIPTION + }; +}; \ No newline at end of file diff --git a/frontend/src/routes/+layout.svelte b/frontend/src/routes/+layout.svelte index e050629..7cd7f1f 100755 --- a/frontend/src/routes/+layout.svelte +++ b/frontend/src/routes/+layout.svelte @@ -1,5 +1,13 @@ -
diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index 2927103..a4e2d83 100755 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -1,13 +1,12 @@ - -

PasteBook

+

{$title}

- PasteBook is an aesthetic, effortless way to share your blocks of text, and - respects your privacy by automatically deleting your pastes. + {$description}

-
- - -
-
-

- This privacy notice for PasteBook ("we," - "us," or "our" ), - describes how and why we might collect, store, use, and/or share ( - "process" ) your information when you use our - services ( "Services" ), such as when you: -

-
    -
  • -

    - Visit our website at https://pastebook.dev , or any website of ours that links to this privacy notice -

    -
  • -
  • -

    - Engage with us in other related ways, including any sales, - marketing, or events -

    -
  • -
-

- Questions or concerns? Reading this privacy notice will - help you understand your privacy rights and choices. If you do not agree - with our policies and practices, please do not use our Services. If you still - have any questions or concerns, please contact us at contact@pastebook.dev. -

-

SUMMARY OF KEY POINTS

-

- This summary provides key points from our privacy notice, but you - can find out more details about any of these topics by clicking the - link following each key point or by using our table of contents - below to find the section you are looking for. -

-

- What personal information do we process? When you - visit, use, or navigate our Services, we may process personal - information depending on how you interact with us and the Services, the - choices you make, and the products and features you use. Learn more - about - personal information you disclose to us - . -

-

- Do we process any sensitive personal information? We do - not process sensitive personal information. -

-

- Do we collect any information from third parties? We do - not collect any information from third parties. -

-

- How do we process your information? We process your - information to provide, improve, and administer our Services, - communicate with you, for security and fraud prevention, and to comply - with law. We may also process your information for other purposes with - your consent. We process your information only when we have a valid - legal reason to do so. Learn more about - how we process your information . -

-

- In what situations and with which parties do we share personal - information? - We may share information in specific situations and with specific third - parties. Learn more about - when and with whom we share your personal information . -

-

- How do we keep your information safe? We have - organizational and technical processes and procedures in place to - protect your personal information. However, no electronic transmission - over the internet or information storage technology can be guaranteed to - be 100% secure, so we cannot promise or guarantee that hackers, - cybercriminals, or other unauthorized third parties will not be able to - defeat our security and improperly collect, access, steal, or modify - your information. Learn more about - how we keep your information safe . -

-

- What are your rights? Depending on where you are - located geographically, the applicable privacy law may mean you have - certain rights regarding your personal information. Learn more about - your privacy rights . -

-

- How do you exercise your rights? The easiest way to exercise - your rights is by contacting us. We will consider and act upon any request - in accordance with applicable data protection laws. -

-

- Want to learn more about what we do with any information we collect? Review the privacy notice in full . -

-

TABLE OF CONTENTS

-

1. WHAT INFORMATION DO WE COLLECT?

-

2. HOW DO WE PROCESS YOUR INFORMATION?

-

- 3. WHAT LEGAL BASES DO WE RELY ON TO PROCESS YOUR PERSONAL INFORMATION? -

-

4. WHEN AND WITH WHOM DO WE SHARE YOUR PERSONAL INFORMATION?

-

5. HOW DO WE HANDLE YOUR SOCIAL LOGINS?

-

6. HOW LONG DO WE KEEP YOUR INFORMATION?

-

7. HOW DO WE KEEP YOUR INFORMATION SAFE?

-

8. DO WE COLLECT INFORMATION FROM MINORS?

-

9. WHAT ARE YOUR PRIVACY RIGHTS?

-

10. CONTROLS FOR DO-NOT-TRACK FEATURES

-

11. DO UNITED STATES RESIDENTS HAVE SPECIFIC PRIVACY RIGHTS?

-

12. DO OTHER REGIONS HAVE SPECIFIC PRIVACY RIGHTS?

-

13. DO WE MAKE UPDATES TO THIS NOTICE?

-

14. HOW CAN YOU CONTACT US ABOUT THIS NOTICE?

-

- 15. HOW CAN YOU REVIEW, UPDATE, OR DELETE THE DATA WE COLLECT FROM YOU? -

-

1. WHAT INFORMATION DO WE COLLECT?

-

Personal information you disclose to us

-

- In Short: - We collect personal information that you provide to us. -

-

- We collect personal information that you voluntarily provide to us when - you register on the Services, express an interest in obtaining - information about us or our products and Services, when you participate - in activities on the Services, or otherwise when you contact us. -

-

- Personal Information Provided by You. The personal information - that we collect depends on the context of your interactions with us and the - Services, the choices you make, and the products and features you use. The - personal information we collect may include the following: -

-
    -
  • names

  • -
  • email addresses

  • -
  • usernames

  • -
  • passwords

  • -
-

- Sensitive Information. We do not process sensitive information. -

-

- Social Media Login Data. We may provide you with the - option to register with us using your existing social media account - details, like your Facebook, X, or other social media account. If you - choose to register in this way, we will collect certain profile - information about you from the social media provider, as described in - the section called "HOW DO WE HANDLE YOUR SOCIAL LOGINS? " below. -

-

- All personal information that you provide to us must be true, complete, - and accurate, and you must notify us of any changes to such personal - information. -

-

Information automatically collected

-

- In Short: - Some information — such as your Internet Protocol (IP) address and/or - browser and device characteristics — is collected automatically when - you visit our Services. -

-

- We automatically collect certain information when you visit, use, or - navigate the Services. This information does not reveal your specific - identity (like your name or contact information) but may include device - and usage information, such as your IP address, browser and device - characteristics, operating system, language preferences, referring URLs, - device name, country, location, information about how and when you use - our Services, and other technical information. This information is - primarily needed to maintain the security and operation of our Services, - and for our internal analytics and reporting purposes. -

-

The information we collect includes:

-
    -
  • -

    - Log and Usage Data. Log and usage data is service-related, diagnostic, - usage, and performance information our servers automatically collect - when you access or use our Services and which we record in log files. - Depending on how you interact with us, this log data may include your - IP address, device information, browser type, and settings and information - about your activity in the Services (such as the date/time stamps associated - with your usage, pages and files viewed, searches, and other actions - you take such as which features you use), device event information (such - as system activity, error reports (sometimes called "crash dumps" - ), and hardware settings). -

    -
  • -
  • -

    - Device Data. We collect device data such as information about - your computer, phone, tablet, or other device you use to access the Services. - Depending on the device used, this device data may include information - such as your IP address (or proxy server), device and application identification - numbers, location, browser type, hardware model, Internet service provider - and/or mobile carrier, operating system, and system configuration information. -

    -
  • -
-

2. HOW DO WE PROCESS YOUR INFORMATION?

-

- In Short: - We process your information to provide, improve, and administer our - Services, communicate with you, for security and fraud prevention, and - to comply with law. We may also process your information for other - purposes with your consent. -

-

- We process your personal information for a variety of reasons, - depending on how you interact with our Services, including: -

-
    -
  • -

    - To facilitate account creation and authentication and otherwise - manage user accounts. We may process your information so you can create and log in to your - account, as well as keep your account in working order. -

    -
  • -
  • -

    - To protect our Services. We may process your information - as part of our efforts to keep our Services safe and secure, including - fraud monitoring and prevention. -

    -
  • -
  • -

    - To save or protect an individual's vital interest. We may process your information when necessary to save or protect an - individual’s vital interest, such as to prevent harm. -

    -
  • -
  • Security**.** __________

  • -
-

- 3. WHAT LEGAL BASES DO WE RELY ON TO PROCESS YOUR INFORMATION? -

-

- In Short: We only process your personal information when - we believe it is necessary and we have a valid legal reason (i.e., legal - basis) to do so under applicable law, like with your consent, to comply - with laws, to provide you with services to enter into or fulfill our contractual - obligations, to protect your rights, or to fulfill our legitimate business - interests. -

-

- If you are located in the EU or UK, this section applies to you. -

-

- The General Data Protection Regulation (GDPR) and UK GDPR require us to - explain the valid legal bases we rely on in order to process your - personal information. As such, we may rely on the following legal bases - to process your personal information: -

-
    -
  • -

    - Consent. We may process your information if you - have given us permission (i.e., consent) to use your personal - information for a specific purpose. You can withdraw your consent at - any time. Learn more about - withdrawing your consent . -

    -
  • -
  • -

    - Legitimate Interests. We may process your information - when we believe it is reasonably necessary to achieve our legitimate - business interests and those interests do not outweigh your interests - and fundamental rights and freedoms. For example, we may process your - personal information for some of the purposes described in order to: -

    -
  • -
  • Diagnose problems and/or prevent fraudulent activities

  • -
  • prevent misuse of the service

  • -
  • -

    - Legal Obligations. We may process your information where - we believe it is necessary for compliance with our legal obligations, - such as to cooperate with a law enforcement body or regulatory agency, - exercise or defend our legal rights, or disclose your information as - evidence in litigation in which we are involved. -

    -
  • -
-
    -
  • - Vital Interests. We may process your information where - we believe it is necessary to protect your vital interests or the vital - interests of a third party, such as situations involving potential threats - to the safety of any person. -
  • -
-

- If you are located in Canada, this section applies to you. -

-

- We may process your information if you have given us specific permission - (i.e., express consent) to use your personal information for a specific - purpose, or in situations where your permission can be inferred (i.e., - implied consent). You can withdraw your consent at any time. -

-

- In some exceptional cases, we may be legally permitted under applicable - law to process your information without your consent, including, for - example: -

-
    -
  • -

    - If collection is clearly in the interests of an individual and - consent cannot be obtained in a timely way -

    -
  • -
  • For investigations and fraud detection and prevention

  • -
  • -

    For business transactions provided certain conditions are met

    -
  • -
  • -

    - If it is contained in a witness statement and the collection is - necessary to assess, process, or settle an insurance claim -

    -
  • -
  • -

    - For identifying injured, ill, or deceased persons and communicating - with next of kin -

    -
  • -
  • -

    - If we have reasonable grounds to believe an individual has been, is, - or may be victim of financial abuse -

    -
  • -
  • -

    - If it is reasonable to expect collection and use with consent would - compromise the availability or the accuracy of the information and - the collection is reasonable for purposes related to investigating a - breach of an agreement or a contravention of the laws of Canada or a - province -

    -
  • -
  • -

    - If disclosure is required to comply with a subpoena, warrant, court - order, or rules of the court relating to the production of records -

    -
  • -
  • -

    - If it was produced by an individual in the course of their - employment, business, or profession and the collection is consistent - with the purposes for which the information was produced -

    -
  • -
  • -

    - If the collection is solely for journalistic, artistic, or literary - purposes -

    -
  • -
  • -

    - If the information is publicly available and is specified by the - regulations -

    -
  • -
-

- 4. WHEN AND WITH WHOM DO WE SHARE YOUR PERSONAL INFORMATION? -

-

- In Short: - We may share information in specific situations described in this - section and/or with the following third parties. -

-

- We may need to share your personal information in the following - situations: -

-
    -
  • - Business Transfers. We may share or transfer your information - in connection with, or during negotiations of, any merger, sale of company - assets, financing, or acquisition of all or a portion of our business to - another company. -
  • -
-

5. HOW DO WE HANDLE YOUR SOCIAL LOGINS?

-

- In Short: - If you choose to register or log in to our Services using a social - media account, we may have access to certain information about you. -

-

- Our Services offer you the ability to register and log in using your - third-party social media account details (like your Facebook or X - logins). Where you choose to do this, we will receive certain profile - information about you from your social media provider. The profile - information we receive may vary depending on the social media provider - concerned, but will often include your name, email address, friends - list, and profile picture, as well as other information you choose to - make public on such a social media platform. -

-

- We will use the information we receive only for the purposes that are - described in this privacy notice or that are otherwise made clear to you - on the relevant Services. Please note that we do not control, and are - not responsible for, other uses of your personal information by your - third-party social media provider. We recommend that you review their - privacy notice to understand how they collect, use, and share your - personal information, and how you can set your privacy preferences on - their sites and apps. -

-

6. HOW LONG DO WE KEEP YOUR INFORMATION?

-

- In Short: - We keep your information for as long as necessary to fulfill the - purposes outlined in this privacy notice unless otherwise required by - law. -

-

- We will only keep your personal information for as long as it is - necessary for the purposes set out in this privacy notice, unless a - longer retention period is required or permitted by law (such as tax, - accounting, or other legal requirements). No purpose in this notice will - require us keeping your personal information for longer than the period - of time in which users have an account with us . -

-

- When we have no ongoing legitimate business need to process your - personal information, we will either delete or anonymize such - information, or, if this is not possible (for example, because your - personal information has been stored in backup archives), then we will - securely store your personal information and isolate it from any further - processing until deletion is possible. -

-

7. HOW DO WE KEEP YOUR INFORMATION SAFE?

-

- In Short: - We aim to protect your personal information through a system of - organizational and technical security measures. -

-

- We have implemented appropriate and reasonable technical and - organizational security measures designed to protect the security of any - personal information we process. However, despite our safeguards and - efforts to secure your information, no electronic transmission over the - Internet or information storage technology can be guaranteed to be 100% - secure, so we cannot promise or guarantee that hackers, cybercriminals, - or other unauthorized third parties will not be able to defeat our - security and improperly collect, access, steal, or modify your - information. Although we will do our best to protect your personal - information, transmission of personal information to and from our - Services is at your own risk. You should only access the Services within - a secure environment. -

-

8. DO WE COLLECT INFORMATION FROM MINORS?

-

- In Short: - We do not knowingly collect data from or market to children under 18 - years of age. -

-

- We do not knowingly collect, solicit data from, or market to children - under 18 years of age, nor do we knowingly sell such personal - information. By using the Services, you represent that you are at least - 18 or that you are the parent or guardian of such a minor and consent to - such minor dependent’s use of the Services. If we learn that personal - information from users less than 18 years of age has been collected, we - will deactivate the account and take reasonable measures to promptly - delete such data from our records. If you become aware of any data we - may have collected from children under age 18, please contact us at - contact@pastebook.dev. -

-

9. WHAT ARE YOUR PRIVACY RIGHTS?

-

- In Short: - Depending on your state of residence in the US or in some regions, - such as the European Economic Area (EEA), United Kingdom (UK), - Switzerland, and Canada , you have rights that allow you greater - access to and control over your personal information. You may review, - change, or terminate your account at any time, depending on your - country, province, or state of residence. -

-

- In some regions (like the EEA, UK, Switzerland, and Canada), you have - certain rights under applicable data protection laws. These may include - the right (i) to request access and obtain a copy of your personal - information, (ii) to request rectification or erasure; (iii) to restrict - the processing of your personal information; (iv) if applicable, to data - portability; and (v) not to be subject to automated decision-making. In - certain circumstances, you may also have the right to object to the - processing of your personal information. You can make such a request by - contacting us by using the contact details provided in the section - " HOW CAN YOU CONTACT US ABOUT THIS NOTICE? " - below. -

-

- We will consider and act upon any request in accordance with applicable - data protection laws. -

-

- If you are located in the EEA or UK and you believe we are unlawfully - processing your personal information, you also have the right to - complain to your Member State data protection authority - or - UK data protection authority . -

-

- If you are located in Switzerland, you may contact the Federal Data Protection and Information Commissioner . -

-

- Withdrawing your consent: If we are relying on your - consent to process your personal information, which may be express - and/or implied consent depending on the applicable law, you have the - right to withdraw your consent at any time. You can withdraw your - consent at any time by contacting us by using the contact details - provided in the section " - HOW CAN YOU CONTACT US ABOUT THIS NOTICE? " below - or updating your preferences. -

-

- However, please note that this will not affect the lawfulness of the - processing before its withdrawal nor, when applicable law allows, will - it affect the processing of your personal information conducted in - reliance on lawful processing grounds other than consent. -

-

Account Information

-

- If you would at any time like to review or change the information in - your account or terminate your account, you can: -

-
    -
  • Log in to your account settings and update your user account.
  • -
-

- Upon your request to terminate your account, we will deactivate or - delete your account and information from our active databases. However, - we may retain some information in our files to prevent fraud, - troubleshoot problems, assist with any investigations, enforce our legal - terms and/or comply with applicable legal requirements. -

-

- If you have questions or comments about your privacy rights, you may - email us at contact@pastebook.dev. -

-

10. CONTROLS FOR DO-NOT-TRACK FEATURES

-

- Most web browsers and some mobile operating systems and mobile - applications include a Do-Not-Track ("DNT") feature or setting - you can activate to signal your privacy preference not to have data - about your online browsing activities monitored and collected. At this - stage, no uniform technology standard for recognizing and implementing - DNT signals has been finalized. As such, we do not currently respond to - DNT browser signals or any other mechanism that automatically - communicates your choice not to be tracked online. If a standard for - online tracking is adopted that we must follow in the future, we will - inform you about that practice in a revised version of this privacy - notice. -

-

- California law requires us to let you know how we respond to web browser - DNT signals. Because there currently is not an industry or legal - standard for recognizing or honoring DNT signals, we do not respond to - them at this time. -

-

- 11. DO UNITED STATES RESIDENTS HAVE SPECIFIC PRIVACY RIGHTS? -

-

- In Short: - If you are a resident of California, Colorado, Connecticut, Delaware, - Florida, Indiana, Iowa, Kentucky, Montana, New Hampshire, New Jersey, - Oregon, Tennessee, Texas, Utah, or Virginia, you may have the right to - request access to and receive details about the personal information - we maintain about you and how we have processed it, correct - inaccuracies, get a copy of, or delete your personal information. You - may also have the right to withdraw your consent to our processing of - your personal information. These rights may be limited in some - circumstances by applicable law. More information is provided below. -

-

Categories of Personal Information We Collect

-

- We have collected the following categories of personal information in - the past twelve (12) months: -

-

Category

-

Examples

-

Collected

-

A. Identifiers

-

- Contact details, such as real name, alias, postal address, telephone or - mobile contact number, unique personal identifier, online identifier, - Internet Protocol address, email address, and account name -

-

YES

-

- B. Personal information as defined in the California Customer Records - statute -

-

- Name, contact information, education, employment, employment history, - and financial information -

-

NO

-

- C. Protected classification characteristics under state or federal law -

-

- Gender, age, date of birth, race and ethnicity, national origin, marital - status, and other demographic data -

-

NO

-

D. Commercial information

-

- Transaction information, purchase history, financial details, and - payment information -

-

NO

-

E. Biometric information

-

Fingerprints and voiceprints

-

NO

-

F. Internet or other similar network activity

-

- Browsing history, search history, online behavior, interest data, and - interactions with our and other websites, applications, systems, and - advertisements -

-

NO

-

G. Geolocation data

-

Device location

-

NO

-

H. Audio, electronic, sensory, or similar information

-

- Images and audio, video or call recordings created in connection with - our business activities -

-

NO

-

I. Professional or employment-related information

-

- Business contact details in order to provide you our Services at a - business level or job title, work history, and professional - qualifications if you apply for a job with us -

-

NO

-

J. Education Information

-

Student records and directory information

-

NO

-

K. Inferences drawn from collected personal information

-

- Inferences drawn from any of the collected personal information listed - above to create a profile or summary about, for example, an individual’s - preferences and characteristics -

-

NO

-

L. Sensitive personal Information

-

NO

-

- We may also collect other personal information outside of these - categories through instances where you interact with us in person, - online, or by phone or mail in the context of: -

-
    -
  • Receiving help through our customer support channels;

  • -
  • Participation in customer surveys or contests; and

  • -
  • -

    - Facilitation in the delivery of our Services and to respond to your - inquiries. -

    -
  • -
-

- We will use and retain the collected personal information as needed to - provide the Services or for: -

-
    -
  • Category A - As long as the user has an account with us

  • -
  • Category H - No data will be collected.

  • -
-

Sources of Personal Information

-

- Learn more about the sources of personal information we collect in - " WHAT INFORMATION DO WE COLLECT?" -

-

How We Use and Share Personal Information

-

- Learn about how we use your personal information in the section, " HOW DO WE PROCESS YOUR INFORMATION?" -

-

Will your information be shared with anyone else?

-

- We may disclose your personal information with our service providers - pursuant to a written contract between us and each service provider. - Learn more about how we disclose personal information to in the section, - " - WHEN AND WITH WHOM DO WE SHARE YOUR PERSONAL INFORMATION? " -

-

- We may use your personal information for our own business purposes, such - as for undertaking internal research for technological development and - demonstration. This is not considered to be "selling" of your - personal information. -

-

- We have not disclosed, sold, or shared any personal information to third - parties for a business or commercial purpose in the preceding twelve - (12) months. We will not sell or share personal information in the - future belonging to website visitors, users, and other consumers. -

-

Your Rights

-

- You have rights under certain US state data protection laws. However, - these rights are not absolute, and in certain cases, we may decline your - request as permitted by law. These rights include: -

-
    -
  • -

    - Right to know whether or not we are processing your - personal data -

    -
  • -
  • Right to access your personal data

  • -
  • -

    - Right to correct inaccuracies in your personal data -

    -
  • -
  • -

    - Right to request the deletion of your personal data -

    -
  • -
  • -

    - Right to obtain a copy of the personal data you previously - shared with us -

    -
  • -
  • -

    - Right to non-discrimination for exercising your rights -

    -
  • -
  • -

    - Right to opt out of the processing of your personal - data if it is used for targeted advertising (or sharing as defined under - California’s privacy law), the sale of personal data, or profiling in - furtherance of decisions that produce legal or similarly significant - effects ("profiling") -

    -
  • -
-

- Depending upon the state where you live, you may also have the following - rights: -

-
    -
  • -

    - Right to obtain a list of the categories of third parties to which - we have disclosed personal data (as permitted by applicable law, - including California's and Delaware's privacy law) -

    -
  • -
  • -

    - Right to obtain a list of specific third parties to which we have - disclosed personal data (as permitted by applicable law, including - Oregon’s privacy law) -

    -
  • -
  • -

    - Right to limit use and disclosure of sensitive personal data (as - permitted by applicable law, including California’s privacy law) -

    -
  • -
  • -

    - Right to opt out of the collection of sensitive data and personal - data collected through the operation of a voice or facial - recognition feature (as permitted by applicable law, including - Florida’s privacy law) -

    -
  • -
-

How to Exercise Your Rights

-

- To exercise these rights, you can contact us by submitting a data subject access request - , by emailing us at contact@pastebook.dev, or by referring to the contact - details at the bottom of this document. -

-

- Under certain US state data protection laws, you can designate an - authorized agent to make a request on your behalf. We may deny a request - from an authorized agent that does not submit proof that they have been - validly authorized to act on your behalf in accordance with applicable - laws. -

-

Request Verification

-

- Upon receiving your request, we will need to verify your identity to - determine you are the same person about whom we have the information in - our system. We will only use personal information provided in your - request to verify your identity or authority to make the request. - However, if we cannot verify your identity from the information already - maintained by us, we may request that you provide additional information - for the purposes of verifying your identity and for security or - fraud-prevention purposes. -

-

- If you submit the request through an authorized agent, we may need to - collect additional information to verify your identity before processing - your request and the agent will need to provide a written and signed - permission from you to submit such request on your behalf. -

-

Appeals

-

- Under certain US state data protection laws, if we decline to take - action regarding your request, you may appeal our decision by emailing - us at contact@pastebook.dev. We will inform you in writing of any action - taken or not taken in response to the appeal, including a written - explanation of the reasons for the decisions. If your appeal is denied, - you may submit a complaint to your state attorney general. -

-

California "Shine The Light" Law

-

- California Civil Code Section 1798.83, also known as the "Shine The - Light" law, permits our users who are California residents to - request and obtain from us, once a year and free of charge, information - about categories of personal information (if any) we disclosed to third - parties for direct marketing purposes and the names and addresses of all - third parties with which we shared personal information in the - immediately preceding calendar year. If you are a California resident - and would like to make such a request, please submit your request in - writing to us by using the contact details provided in the section - " HOW CAN YOU CONTACT US ABOUT THIS NOTICE?" -

-

12. DO OTHER REGIONS HAVE SPECIFIC PRIVACY RIGHTS?

-

- In Short: You may have additional rights based on the - country you reside in. -

-

- Australia and - New Zealand -

-

- We collect and process your personal information under the obligations - and conditions set by Australia's Privacy Act 1988 and New - Zealand's Privacy Act 2020 (Privacy Act). -

-

- This privacy notice satisfies the notice requirements defined in both - Privacy Acts, in particular: what personal information we collect from - you, from which sources, for which purposes, and other recipients of - your personal information. -

-

- If you do not wish to provide the personal information necessary to - fulfill their applicable purpose, it may affect our ability to provide - our services, in particular: -

-
    -
  • offer you the products or services that you want

  • -
  • respond to or help with your requests

  • -
  • manage your account with us

  • -
  • confirm your identity and protect your account

  • -
-

- At any time, you have the right to request access to or correction of - your personal information. You can make such a request by contacting us - by using the contact details provided in the section "HOW CAN YOU REVIEW, UPDATE, OR DELETE THE DATA WE COLLECT FROM YOU? " -

-

- If you believe we are unlawfully processing your personal information, - you have the right to submit a complaint about a breach of the - Australian Privacy Principles to the Office of the Australian Information Commissioner - and a breach of New Zealand's Privacy Principles to the - Office of New Zealand Privacy Commissioner . -

-

Republic of South Africa

-

- At any time, you have the right to request access to or correction of - your personal information. You can make such a request by contacting us - by using the contact details provided in the section " HOW CAN YOU REVIEW, UPDATE, OR DELETE THE DATA WE COLLECT FROM YOU?" -

-

- If you are unsatisfied with the manner in which we address any complaint - with regard to our processing of personal information, you can contact - the office of the regulator, the details of which are: -

-

- The Information Regulator (South Africa) -

-

- General enquiries: enquiries@inforegulator.org.za -

-

- Complaints (complete POPIA/PAIA form 5): PAIAComplaints@inforegulator.org.za - & - POPIAComplaints@inforegulator.org.za -

-

13. DO WE MAKE UPDATES TO THIS NOTICE?

-

- In Short: Yes, we will update this notice as necessary - to stay compliant with relevant laws. -

-

- We may update this privacy notice from time to time. The updated version - will be indicated by an updated "Revised" date at the top of - this privacy notice. If we make material changes to this privacy notice, - we may notify you either by prominently posting a notice of such changes - or by directly sending you a notification. We encourage you to review - this privacy notice frequently to be informed of how we are protecting - your information. -

-

14. HOW CAN YOU CONTACT US ABOUT THIS NOTICE?

-

- If you have questions or comments about this notice, you may email us at - contact@pastebook.dev or contact us by post at: -

-

PasteBook

-

__________

-

__________

-

- 15. HOW CAN YOU REVIEW, UPDATE, OR DELETE THE DATA WE COLLECT FROM - YOU? -

-

- Based on the applicable laws of your country or state of residence in - the US, you may have the right to request access to the personal - information we collect from you, details about how we have processed it, - correct inaccuracies, or delete your personal information. You may also - have the right to withdraw your consent to our processing of your - personal information. These rights may be limited in some circumstances - by applicable law. To request to review, update, or delete your personal - information, please fill out and submit a data subject access request - . -

-

-
-
-
- - - - - - - - - - - From 42061253685946815258a88dd5fcfc2b917f9520 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 6 Dec 2024 13:44:20 -0500 Subject: [PATCH 091/188] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index e97f64e..188717e 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,9 @@ services: image: ghcr.io/loudbook/pastebook-frontend:latest ports: - "3000:3000" + environment: + - TITLE=PasteBook + - DESCRIPTION=PasteBook is an aesthetic, effortless way to share your blocks of text, and respects your privacy by automatically deleting your pastes. depends_on: - backend networks: From 40fba1f5a2ffd0fa20f012aabb3df5769c630943 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 6 Dec 2024 13:55:10 -0500 Subject: [PATCH 092/188] Update Embeds --- frontend/src/routes/+layout.svelte | 2 +- frontend/src/routes/+page.svelte | 2 +- frontend/src/routes/new/+page.svelte | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/frontend/src/routes/+layout.svelte b/frontend/src/routes/+layout.svelte index 7cd7f1f..75cf04c 100755 --- a/frontend/src/routes/+layout.svelte +++ b/frontend/src/routes/+layout.svelte @@ -4,7 +4,7 @@ let { data }: { data: PageData } = $props(); const newTitle = data.title || 'PasteBook'; - const newDescription = data.description || 'PasteBook is an aesthetic, effortless way to share your blocks of text, and respects your privacy by automatically deleting your pastes. '; + const newDescription = data.description || 'PasteBook is an aesthetic, effortless way to share your blocks of text, and respects your privacy by automatically deleting your pastes.'; title.set(newTitle); description.set(newDescription); diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index a4e2d83..ea6d6b9 100755 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -31,7 +31,7 @@ diff --git a/frontend/src/routes/new/+page.svelte b/frontend/src/routes/new/+page.svelte index df94770..087f569 100755 --- a/frontend/src/routes/new/+page.svelte +++ b/frontend/src/routes/new/+page.svelte @@ -7,7 +7,7 @@ import Pulltab from "../../components/pulltab/Pulltab.svelte"; import Setting from "../../components/settings/Setting.svelte"; - import { expire, wrap } from "$lib/stores"; + import { expire, wrap, title, description } from "$lib/stores"; import DropDown from "../../components/settings/DropDown.svelte"; import { onMount } from "svelte"; @@ -96,11 +96,10 @@ - - + From 0c1f695499f24ea42151836354fd606eabcddd80 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 6 Dec 2024 13:58:34 -0500 Subject: [PATCH 093/188] Update Page Title --- frontend/src/app.html | 1 - frontend/src/routes/+layout.svelte | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/app.html b/frontend/src/app.html index a1f4f0e..419eb32 100755 --- a/frontend/src/app.html +++ b/frontend/src/app.html @@ -30,7 +30,6 @@ rel="stylesheet" /> - PasteBook %sveltekit.head% diff --git a/frontend/src/routes/+layout.svelte b/frontend/src/routes/+layout.svelte index 75cf04c..af79301 100755 --- a/frontend/src/routes/+layout.svelte +++ b/frontend/src/routes/+layout.svelte @@ -1,6 +1,7 @@
From e6266b3b89aa1c502d1ba031bfe7d804e331409f Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 6 Dec 2024 14:10:27 -0500 Subject: [PATCH 094/188] Update build-and-deploy.yml --- .github/workflows/build-and-deploy.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 3fa83e2..cff9fa9 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -77,9 +77,13 @@ jobs: uses: docker/build-push-action@v3 with: context: ./frontend + build-args: | + COMMIT_HASH=${{ env.hash }} file: ./frontend/Dockerfile push: true - tags: ${{ secrets.DOCKER_USERNAME }}/pastebook-frontend:latest + tags: | + ${{ secrets.DOCKER_USERNAME }}/pastebook-frontend:latest + ${{ secrets.DOCKER_USERNAME }}/pastebook-frontend:${{ env.hash }} - name: Build and push backend Docker image to Docker Hub uses: docker/build-push-action@v3 @@ -87,4 +91,6 @@ jobs: context: ./backend file: ./backend/Dockerfile push: true - tags: ${{ secrets.DOCKER_USERNAME }}/pastebook-backend:latest + tags: | + ${{ secrets.DOCKER_USERNAME }}/pastebook-backend:latest + ${{ secrets.DOCKER_USERNAME }}/pastebook-backend:${{ env.hash }} From f26e21223abcd7fe012cdde19979da2a7db6dcd0 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 6 Dec 2024 16:21:59 -0500 Subject: [PATCH 095/188] Change loudbook to loudbooks --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 188717e..35df8da 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Start by creating a file named `docker-compose.yml`. Add the content below. ```yml services: backend: - image: ghcr.io/loudbook/pastebook-backend:latest + image: ghcr.io/loudbooks/pastebook-backend:latest ports: - "8080:8080" environment: @@ -29,7 +29,7 @@ services: - pastebook-network frontend: - image: ghcr.io/loudbook/pastebook-frontend:latest + image: ghcr.io/loudbooks/pastebook-frontend:latest ports: - "3000:3000" environment: From 9b301cfadb97e95966ecb8fa5a1bd36f7f814fb4 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 6 Dec 2024 16:31:27 -0500 Subject: [PATCH 096/188] Update README.md --- README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 35df8da..06a62ef 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,8 @@ services: ports: - "3000:3000" environment: - - TITLE=PasteBook - - DESCRIPTION=PasteBook is an aesthetic, effortless way to share your blocks of text, and respects your privacy by automatically deleting your pastes. + - TITLE= + - DESCRIPTION= depends_on: - backend networks: @@ -62,7 +62,10 @@ networks: driver: bridge ``` ### Configuration -All of the following values must be changed. +> [!CAUTION] +> Do not change any prefilled configurations other than ones listen below. You will break things. + +**Required configurations:**
`S3_ACCESS_KEY_ID` - The access key associated with your R2 bucket, S3 bucket, etc. @@ -71,6 +74,12 @@ All of the following values must be changed. `S3_ENDPOINT` - The endpoint associated with your R2 bucket, S3 bucket, etc. +**Optional configurations:** +
+`TITLE` - The title to be used around PasteBook. + +`DESCRIPTION` - The description to be used in embeds and on the home page of PasteBook. + ### Creation Run the following. ``` From c721d3e7cd99c47efa174deab65376725c5eb478 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Fri, 6 Dec 2024 16:41:03 -0500 Subject: [PATCH 097/188] Fix Deprecation --- frontend/src/routes/+layout.svelte | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/src/routes/+layout.svelte b/frontend/src/routes/+layout.svelte index af79301..d5ab158 100755 --- a/frontend/src/routes/+layout.svelte +++ b/frontend/src/routes/+layout.svelte @@ -1,9 +1,11 @@ From 2e2d495112d989ceed5c9d4842bd3696b21f0e7b Mon Sep 17 00:00:00 2001 From: Loudbook Date: Sat, 7 Dec 2024 19:53:04 -0500 Subject: [PATCH 127/188] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index edfecdf..dd6af11 100644 --- a/README.md +++ b/README.md @@ -19,14 +19,19 @@ Create a file by the name of `.env` in the same directory as `docker-compose.yml TITLE= DESCRIPTION= DISABLE_NEW= +FAVICON_URL= ``` +All of the following are optional. You can leave it all blank, or not even have a `.env` file at all. + `TITLE` - The title to be used around PasteBook. `DESCRIPTION` - The description to be used in embeds and on the home page of PasteBook. `DISABLE_NEW` - Disables the new paste page. API is still accessible. +`FAVICON_URL` - The URL that the favicon will be provided with. + ### Creation Run the following. ```bash From a807ae21cf8a3b50056dad6ac7972fb528b05f8d Mon Sep 17 00:00:00 2001 From: Loudbook Date: Sat, 7 Dec 2024 19:57:13 -0500 Subject: [PATCH 128/188] Render HTML for description --- frontend/src/routes/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index a63679f..b2b9023 100755 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -18,7 +18,7 @@

{$title}

- {$description} + {@html $description}

+

{$title}

+
+ + + \ No newline at end of file diff --git a/frontend/src/components/svg/SVGPasteBook.svelte b/frontend/src/components/svg/SVGPasteBook.svelte deleted file mode 100755 index 8d449ec..0000000 --- a/frontend/src/components/svg/SVGPasteBook.svelte +++ /dev/null @@ -1,158 +0,0 @@ - - - -
- - - - - - - - - - - -
-
- - \ No newline at end of file diff --git a/frontend/src/lib/stores.ts b/frontend/src/lib/stores.ts index 1897b13..b44bae9 100755 --- a/frontend/src/lib/stores.ts +++ b/frontend/src/lib/stores.ts @@ -1,7 +1,7 @@ import { type Writable, writable } from "svelte/store"; import type { Issue } from "$lib/issue"; -export const loadProgress = writable(0); +export const loadProgress = writable(false); export const writableContent = writable(""); export const writableTitle = writable(""); diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index b2b9023..1ec4b02 100755 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -2,6 +2,7 @@ import Mode from "../components/Mode.svelte"; import { onMount } from "svelte"; import { title, description } from "$lib/stores"; + import LoadingTitle from "../components/image/LoadingTitle.svelte"; export const commitHash = import.meta.env.VITE_COMMIT_HASH || 'unknown'; let width = 0; @@ -16,6 +17,7 @@ +

{$title}

{@html $description} diff --git a/frontend/src/routes/[pastes=paste]/[slug]/+page.svelte b/frontend/src/routes/[pastes=paste]/[slug]/+page.svelte index c4c9356..c672143 100755 --- a/frontend/src/routes/[pastes=paste]/[slug]/+page.svelte +++ b/frontend/src/routes/[pastes=paste]/[slug]/+page.svelte @@ -6,7 +6,7 @@ import { loadProgress, severes, warnings } from "$lib/stores"; import { formatTimeSince, formatTimeUntil } from "$lib/timehandler"; import { onMount, tick } from "svelte"; - import SVGPasteBook from "../../../components/svg/SVGPasteBook.svelte"; + import LoadingTitle from "../../../components/image/LoadingTitle.svelte"; import Highlight from "../../../components/Highlight.svelte"; export let data; @@ -42,7 +42,7 @@ }); content.then(() => { - loadProgress.set(100); + loadProgress.set(true); tick(); }); @@ -117,7 +117,7 @@

- +
Date: Sat, 7 Dec 2024 20:23:44 -0500 Subject: [PATCH 133/188] Remove loading title on about page --- frontend/src/routes/+page.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index 1ec4b02..a3ceac9 100755 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -17,7 +17,6 @@ -

{$title}

{@html $description} From 8276849299f08e0f825f4371147aa07d8df92376 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Sat, 7 Dec 2024 20:24:00 -0500 Subject: [PATCH 134/188] Remove uneccessary import --- frontend/src/routes/+page.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index a3ceac9..b2b9023 100755 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -2,7 +2,6 @@ import Mode from "../components/Mode.svelte"; import { onMount } from "svelte"; import { title, description } from "$lib/stores"; - import LoadingTitle from "../components/image/LoadingTitle.svelte"; export const commitHash = import.meta.env.VITE_COMMIT_HASH || 'unknown'; let width = 0; From cb32252aae16017ae0f25ed5f202720b8df68d17 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Sat, 7 Dec 2024 20:24:47 -0500 Subject: [PATCH 135/188] Update build-and-deploy.yml --- .github/workflows/build-and-deploy.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 0511509..58d0850 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -7,12 +7,6 @@ on: - backend/** branches: - master - pull_request: - paths: - - frontend/** - - backend/** - branches: - - master jobs: build: From b15b132a06353dd7e5d7f39198b475abcc12ef9a Mon Sep 17 00:00:00 2001 From: Loudbook Date: Sat, 7 Dec 2024 22:25:56 -0500 Subject: [PATCH 136/188] Fix line number link --- frontend/src/components/Content.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/components/Content.svelte b/frontend/src/components/Content.svelte index d3962c9..8c187ba 100755 --- a/frontend/src/components/Content.svelte +++ b/frontend/src/components/Content.svelte @@ -239,7 +239,6 @@ on:click={clickNumber} tabindex="0" on:keydown={() => {}} - href=null > Date: Sun, 8 Dec 2024 19:12:33 -0500 Subject: [PATCH 137/188] Update ID migration --- .../pastebook/mongo/MigrationHandler.kt | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/MigrationHandler.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/MigrationHandler.kt index 7ea4671..fce5770 100644 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/MigrationHandler.kt +++ b/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/MigrationHandler.kt @@ -1,6 +1,6 @@ package dev.loudbook.pastebook.mongo -import dev.loudbook.pastebook.data.User +import org.bson.Document import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.boot.CommandLineRunner @@ -31,12 +31,26 @@ class MigrationHandler(private val mongoTemplate: MongoTemplate) : CommandLineRu logger.info("Beginning migration of missing IDs...") - val query = Query(Criteria.where("id").exists(false)) - val update = Update().set("id", UUID.randomUUID().toString()) - val result = mongoTemplate.updateMulti(query, update, User::class.java) + val users = mongoTemplate.findAll(Document::class.java, "users") - if (result.modifiedCount > 0) { - logger.info("Fixed ${result.modifiedCount} missing IDs.") + var result = 0 + + users.forEach { + val id = it.getString("id") + if (id == null) { + val newId = UUID.randomUUID().toString() + val query = Query(Criteria.where("_id").`is`(it.getObjectId("_id"))) + val update = Update().set("id", newId) + mongoTemplate.updateFirst(query, update, "users") + logger.info("Fixed missing ID for user ${it.getString("ip")}") + + result++ + } + } + + + if (result > 0) { + logger.info("Fixed ${result} missing IDs.") } else { logger.info("No missing IDs found.") } From 1e1255e20eaab39bcdb12b70e739b5ed4bc3a013 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Mon, 9 Dec 2024 14:12:05 -0500 Subject: [PATCH 138/188] Use margin as opposed to padding --- frontend/src/components/Toolbar.svelte | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/Toolbar.svelte b/frontend/src/components/Toolbar.svelte index ae24214..226184d 100755 --- a/frontend/src/components/Toolbar.svelte +++ b/frontend/src/components/Toolbar.svelte @@ -82,8 +82,9 @@ border: none; color: gray; - padding-left: 20px; - padding-right: 30px; + margin-left: 20px; + margin-right: 30px; + padding: 0; background-color: transparent; outline: none; @@ -98,7 +99,7 @@ @media (max-width: 600px) { font-size: 0.6rem; - padding: 0 0 0 20px; + margin: 0 0 0 20px; } } @@ -107,7 +108,7 @@ @media (max-width: 600px) { font-size: 0.6rem; - padding-right: 20px; + margin-right: 20px; } } @@ -117,10 +118,10 @@ } #main { - padding-left: 30px; + margin-left: 30px; @media (max-width: 600px) { - padding-left: 20px; + margin-left: 20px; } } From 9e92335337d532e88bcaac65a30a82b319ed8431 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Mon, 9 Dec 2024 20:21:39 -0500 Subject: [PATCH 139/188] Begin rust rewrite --- backend/.gitignore | 40 --- backend/Dockerfile | 10 - backend/build.gradle.kts | 62 ----- backend/gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - backend/gradlew | 252 ------------------ backend/gradlew.bat | 94 ------- backend/settings.gradle.kts | 1 - backend/src/aws_service.rs | 82 ++++++ backend/src/controllers/get_controller.rs | 84 ++++++ backend/src/controllers/mod.rs | 2 + backend/src/controllers/upload_controller.rs | 101 +++++++ backend/src/delete_service.rs | 90 +++++++ .../dev/loudbook/pastebook/BucketUtils.kt | 23 -- .../dev/loudbook/pastebook/ContentScanner.kt | 25 -- .../dev/loudbook/pastebook/DeleteHandler.kt | 63 ----- .../kotlin/dev/loudbook/pastebook/IPUtils.kt | 19 -- .../pastebook/PasteBookApplication.kt | 14 - .../pastebook/config/Configuration.kt | 11 - .../loudbook/pastebook/config/WebConfig.kt | 13 - .../pastebook/controllers/GetController.kt | 97 ------- .../pastebook/controllers/UploadController.kt | 89 ------- .../dev/loudbook/pastebook/data/PasteDTO.kt | 6 - .../pastebook/data/PastePrivateDTO.kt | 8 - .../dev/loudbook/pastebook/data/R2Service.kt | 72 ----- .../dev/loudbook/pastebook/data/User.kt | 8 - .../dev/loudbook/pastebook/data/UserDTO.kt | 3 - .../pastebook/mongo/MigrationHandler.kt | 63 ----- .../pastebook/mongo/PasteRepository.kt | 13 - .../loudbook/pastebook/mongo/UserService.kt | 40 --- .../pastebook/mongo/UsersRepository.kt | 10 - backend/src/main/resources/application.yml | 15 -- backend/src/models/mod.rs | 2 + backend/src/models/paste.rs | 38 +++ backend/src/models/user.rs | 29 ++ backend/src/mongodb_service.rs | 80 ++++++ backend/src/mongoresult.rs | 3 + .../pastebook/PasteBookApplicationTests.kt | 13 - backend/src/utils/iputils.rs | 22 ++ backend/src/utils/mod.rs | 1 + 40 files changed, 534 insertions(+), 1071 deletions(-) delete mode 100644 backend/.gitignore delete mode 100644 backend/Dockerfile delete mode 100644 backend/build.gradle.kts delete mode 100644 backend/gradle/wrapper/gradle-wrapper.jar delete mode 100644 backend/gradle/wrapper/gradle-wrapper.properties delete mode 100755 backend/gradlew delete mode 100644 backend/gradlew.bat delete mode 100644 backend/settings.gradle.kts create mode 100644 backend/src/aws_service.rs create mode 100644 backend/src/controllers/get_controller.rs create mode 100644 backend/src/controllers/mod.rs create mode 100644 backend/src/controllers/upload_controller.rs create mode 100644 backend/src/delete_service.rs delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/BucketUtils.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/ContentScanner.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/DeleteHandler.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/IPUtils.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/PasteBookApplication.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/config/Configuration.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/config/WebConfig.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/controllers/GetController.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/controllers/UploadController.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/data/PasteDTO.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/data/PastePrivateDTO.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/data/R2Service.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/data/User.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/data/UserDTO.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/mongo/MigrationHandler.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/mongo/PasteRepository.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/mongo/UserService.kt delete mode 100644 backend/src/main/kotlin/dev/loudbook/pastebook/mongo/UsersRepository.kt delete mode 100644 backend/src/main/resources/application.yml create mode 100644 backend/src/models/mod.rs create mode 100644 backend/src/models/paste.rs create mode 100644 backend/src/models/user.rs create mode 100644 backend/src/mongodb_service.rs create mode 100644 backend/src/mongoresult.rs delete mode 100644 backend/src/test/kotlin/dev/loudbook/pastebook/pastebook/PasteBookApplicationTests.kt create mode 100644 backend/src/utils/iputils.rs create mode 100644 backend/src/utils/mod.rs diff --git a/backend/.gitignore b/backend/.gitignore deleted file mode 100644 index 44d2e86..0000000 --- a/backend/.gitignore +++ /dev/null @@ -1,40 +0,0 @@ -HELP.md -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ - -### Kotlin ### -.kotlin \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile deleted file mode 100644 index 86a4f1b..0000000 --- a/backend/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ - -FROM openjdk:23-slim - -WORKDIR /pastebook-backend - -COPY build/libs/pastebook.jar pastebook.jar - -EXPOSE 8080 - -ENTRYPOINT ["java", "-jar", "pastebook.jar"] \ No newline at end of file diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts deleted file mode 100644 index 0ffff89..0000000 --- a/backend/build.gradle.kts +++ /dev/null @@ -1,62 +0,0 @@ -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -plugins { - id("org.springframework.boot") version "3.4.0" - id("io.spring.dependency-management") version "1.1.6" - kotlin("jvm") version "2.1.0" - kotlin("plugin.spring") version "2.1.0" -} -val springCloudVersion by extra("2023.0.1") - -group = "dev.loudbook" -version = "0.0.1-SNAPSHOT" - -java { - sourceCompatibility = JavaVersion.VERSION_23 - targetCompatibility = JavaVersion.VERSION_23 -} - -repositories { - mavenCentral() -} - -dependencies { - implementation("org.springframework.boot:spring-boot-starter-data-mongodb") - implementation("org.springframework.boot:spring-boot-starter-web") - implementation("com.fasterxml.jackson.module:jackson-module-kotlin") - implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("com.github.vladimir-bukhtoyarov:bucket4j-core:8.0.1") - testImplementation("org.springframework.boot:spring-boot-starter-test") - implementation("com.google.code.gson:gson:2.11.0") - implementation("me.paulschwarz:spring-dotenv:4.0.0") - implementation("commons-validator:commons-validator:1.8.0") - implementation("software.amazon.awssdk:s3:2.29.29") -} - -dependencyManagement { - imports { - mavenBom("org.springframework.cloud:spring-cloud-dependencies:$springCloudVersion") - } -} - -tasks.withType { - compilerOptions { - freeCompilerArgs.add("-Xjsr305=strict") - jvmTarget.set(JvmTarget.JVM_23) - } -} - -tasks.bootJar { - archiveBaseName.set("pastebook") - archiveVersion.set("") - archiveClassifier.set("") -} - -tasks.withType { - useJUnitPlatform() -} - -configurations.implementation { - exclude(group = "commons-logging", module = "commons-logging") -} \ No newline at end of file diff --git a/backend/gradle/wrapper/gradle-wrapper.jar b/backend/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index a4b76b9530d66f5e68d973ea569d8e19de379189..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X diff --git a/backend/gradle/wrapper/gradle-wrapper.properties b/backend/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e2847c8..0000000 --- a/backend/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/backend/gradlew b/backend/gradlew deleted file mode 100755 index f5feea6..0000000 --- a/backend/gradlew +++ /dev/null @@ -1,252 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/backend/gradlew.bat b/backend/gradlew.bat deleted file mode 100644 index 9d21a21..0000000 --- a/backend/gradlew.bat +++ /dev/null @@ -1,94 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/backend/settings.gradle.kts b/backend/settings.gradle.kts deleted file mode 100644 index 0c750f3..0000000 --- a/backend/settings.gradle.kts +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = "PasteBook" diff --git a/backend/src/aws_service.rs b/backend/src/aws_service.rs new file mode 100644 index 0000000..50c02d9 --- /dev/null +++ b/backend/src/aws_service.rs @@ -0,0 +1,82 @@ +use anyhow::Result; +use aws_sdk_s3::config::{Credentials, Region, SharedCredentialsProvider}; +use aws_sdk_s3::primitives::ByteStream; +use aws_sdk_s3::{Client, Config}; + +pub struct AWSService { + client: Client, + bucket_name: String, +} + +impl AWSService { + pub async fn new(endpoint: &str, bucket_name: &str, access_key: &str, secret_key: &str) -> Result { + let region = Region::new("auto"); + let credentials = Credentials::from_keys(access_key, secret_key, None); + let shared_credentials = SharedCredentialsProvider::new(credentials); + + let config = Config::builder() + .region(region) + .credentials_provider(shared_credentials) + .endpoint_url(endpoint) + .build(); + + let client = Client::from_conf(config); + + Ok(Self { + client, + bucket_name: bucket_name.to_string(), + }) + } + + pub async fn get_file(&self, key: &str) -> Result> { + let resp = self + .client + .get_object() + .bucket(&self.bucket_name) + .key(key) + .send() + .await?; + + let data = resp.body.collect().await?; + Ok(data.into_bytes().to_vec()) + } + + pub async fn put_file(&self, key: &str, data: &[u8]) -> Result<()> { + self.client + .put_object() + .bucket(&self.bucket_name) + .key(key) + .body(ByteStream::from(data.to_vec())) + .send() + .await?; + Ok(()) + } + + pub async fn delete_file(&self, key: &str) -> Result<()> { + self.client + .delete_object() + .bucket(&self.bucket_name) + .key(key) + .send() + .await?; + Ok(()) + } + + pub async fn list_files(&self) -> Result> { + let resp = self + .client + .list_objects_v2() + .bucket(&self.bucket_name) + .send() + .await?; + + let mut keys = Vec::new(); + for object in resp.contents.unwrap_or_default() { + if let Some(key) = object.key { + keys.push(key); + } + } + + Ok(keys) + } +} diff --git a/backend/src/controllers/get_controller.rs b/backend/src/controllers/get_controller.rs new file mode 100644 index 0000000..bcc6e9e --- /dev/null +++ b/backend/src/controllers/get_controller.rs @@ -0,0 +1,84 @@ +use crate::aws_service::AWSService; +use actix_web::{ + web, HttpRequest, HttpResponse, Responder, +}; +use serde::Deserialize; +use std::sync::Arc; +use crate::mongodb_service::MongoService; + +#[derive(Deserialize)] +pub struct ContentQuery { + pub compress: Option, +} + +pub async fn get_metadata_handler( + mongo_service: web::Data>, + request: HttpRequest, + path: web::Path, +) -> impl Responder { + let ip = extract_ip(&request); + if mongo_service.is_user_banned(&ip).await.expect("Failed to check if user is banned") { + return HttpResponse::Forbidden().body("Prohibited"); + } + + match mongo_service.get_paste_metadata(&path).await { + Ok(Some(metadata)) => { + let user = mongo_service.get_user(&metadata.creator_ip).await.unwrap(); + + let public_dto = metadata.to_public_dto(user.unwrap().to_dto()); + HttpResponse::Ok().json(public_dto) + } + Ok(None) => HttpResponse::NotFound().body("Not Found"), + Err(_) => HttpResponse::InternalServerError().body("Internal Server Error"), + } +} + +pub async fn get_content_handler( + aws_service: web::Data>, + mongo_service: web::Data>, + request: HttpRequest, + path: web::Path, + query: web::Query, +) -> impl Responder { + let compress = query.compress.unwrap_or(true); + let ip = extract_ip(&request); + + if mongo_service.is_user_banned(&ip).await.expect("Failed to check if user is banned") { + return HttpResponse::Forbidden().body("Prohibited"); + } + + mongo_service.increment_requests(&ip).await.expect("Failed to increment requests"); + + match aws_service.get_file(&path).await { + Ok(data) => { + if compress { + let compressed = compress_data(&data); + HttpResponse::Ok() + .content_type("text/plain; charset=utf-8") + .append_header(("Content-Encoding", "gzip")) + .body(compressed) + } else { + HttpResponse::Ok() + .content_type("text/plain; charset=utf-8") + .body(data) + } + } + Err(_) => HttpResponse::NotFound().body("File not found"), + } +} + +fn compress_data(data: &[u8]) -> Vec { + use flate2::write::GzEncoder; + use flate2::Compression; + use std::io::Write; + + let mut encoder = GzEncoder::new(Vec::new(), Compression::default()); + encoder.write_all(data).expect("Failed to write data"); + encoder.finish().expect("Failed to finish compression") +} + +fn extract_ip(req: &HttpRequest) -> String { + req.peer_addr() + .map(|addr| addr.ip().to_string()) + .unwrap_or_else(|| "unknown".to_string()) +} diff --git a/backend/src/controllers/mod.rs b/backend/src/controllers/mod.rs new file mode 100644 index 0000000..a2b619e --- /dev/null +++ b/backend/src/controllers/mod.rs @@ -0,0 +1,2 @@ +pub mod get_controller; +pub mod upload_controller; \ No newline at end of file diff --git a/backend/src/controllers/upload_controller.rs b/backend/src/controllers/upload_controller.rs new file mode 100644 index 0000000..1edc330 --- /dev/null +++ b/backend/src/controllers/upload_controller.rs @@ -0,0 +1,101 @@ +use crate::aws_service::AWSService; +use crate::models::paste::Paste; +use crate::mongodb_service::MongoService; +use crate::utils::iputils::IPUtils; +use actix_web::{web, HttpRequest, HttpResponse, Responder}; +use rand::{distributions::Alphanumeric, thread_rng, Rng}; +use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; + +pub async fn upload_handler( + aws_service: web::Data>, + mongo_service: web::Data>, + req: HttpRequest, + body: String, +) -> impl Responder { + let title = req + .headers() + .get("title") + .and_then(|v| v.to_str().ok()) + .unwrap_or(""); + if title.is_empty() { + return HttpResponse::BadRequest().body("Title is required"); + } + + let report_book = req + .headers() + .get("reportBook") + .map(|v| v.to_str().unwrap_or("false") == "true") + .unwrap_or(false); + + let wrap = req + .headers() + .get("wrap") + .map(|v| v.to_str().unwrap_or("false") == "true") + .unwrap_or(false); + + let mut expires = req + .headers() + .get("expires") + .and_then(|v| v.to_str().ok()?.parse::().ok()) + .unwrap_or_else(|| 86_400_000); + + let since_the_epoch = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() as u64; + + if expires < 60_000 { + return HttpResponse::BadRequest().body("Expire time too short"); + } + if expires < since_the_epoch { + expires += since_the_epoch; + } + if expires > since_the_epoch + 2_765_000_000 { + return HttpResponse::BadRequest().body("Expire time too long"); + } + + let ip = match IPUtils::get_ip_from_request(&req) { + Some(ip) => ip, + None => return HttpResponse::BadRequest().body("Failed to get IP"), + }; + + let file_id = generate_random_string(5); + + let paste = Paste { + id: Some(file_id.clone()), + title: title.to_string(), + created: since_the_epoch, + report_book, + wrap, + creator_ip: ip.clone(), + expires, + }; + + if let Err(e) = aws_service.put_file(&file_id, (&body).as_ref()).await { + return HttpResponse::InternalServerError().body(format!("Failed to upload file: {:?}", e)); + } + if let Err(e) = mongo_service.put_paste(paste).await { + return HttpResponse::InternalServerError().body(format!("Failed to save to database: {:?}", e)); + } + + let host_domain = req + .headers() + .get("X-Domain-Name") + .and_then(|v| v.to_str().ok()); + let response_body = if let Some(domain) = host_domain { + format!("https://{}/p/{}", domain, file_id) + } else { + file_id.clone() + }; + + HttpResponse::Ok().body(response_body) +} + +fn generate_random_string(length: usize) -> String { + thread_rng() + .sample_iter(&Alphanumeric) + .take(length) + .map(char::from) + .collect() +} diff --git a/backend/src/delete_service.rs b/backend/src/delete_service.rs new file mode 100644 index 0000000..c101f21 --- /dev/null +++ b/backend/src/delete_service.rs @@ -0,0 +1,90 @@ +use std::sync::Arc; +use std::time::Duration; +use chrono::Utc; +use futures_util::StreamExt; +use log::{error, warn}; +use tokio::spawn; +use tokio::time::interval; +use crate::aws_service::AWSService; +use crate::mongodb_service::MongoService; + +pub struct DeleteHandler { + aws_service: Arc, + mongo_service: Arc, +} + +impl DeleteHandler { + pub fn new(aws_service: Arc, mongo_service: Arc) -> Self { + let handler = Self { + aws_service, + mongo_service, + }; + + handler.start_delete_loop(); + handler + } + + pub(crate) fn start_delete_loop(&self) { + let aws_service = Arc::clone(&self.aws_service); + let mongo_service = Arc::clone(&self.mongo_service); + + spawn(async move { + let mut interval = interval(Duration::from_secs(600)); + loop { + interval.tick().await; + if let Err(err) = Self::delete_files(&aws_service, &mongo_service).await { + error!("Error during deletion process: {}", err); + } + } + }); + } + + async fn delete_files( + aws_service: &Arc, + mongo_service: &Arc, + ) -> Result<(), String> { + let now = Utc::now().timestamp_millis(); + let mut deletable_pastes = Vec::new(); + let mut all_pastes = Vec::new(); + + if let Ok(mut pastes_cursor) = mongo_service.get_all_pastes_metadata().await { + while let Some(paste) = pastes_cursor.next().await { + let paste = paste.expect("Failed to get paste"); + + if paste.expires > 0 && paste.expires < now as u64 { + deletable_pastes.push(paste.clone()); + } + + all_pastes.push(paste); + } + } + + for paste in &deletable_pastes { + let paste_id = paste.id.as_deref().unwrap_or_default(); + if let Err(err) = mongo_service.delete_paste(paste_id).await { + error!("Failed to delete paste from database: {:?}", err); + } + if let Some(id) = &paste.id { + if let Err(err) = mongo_service.delete_paste(id).await { + error!("Failed to delete paste file: {}", err); + } + } else { + error!("Paste ID is missing for: {:?}", paste); + } + } + + if let Ok(file_names) = aws_service.list_files().await { + for file_name in file_names { + if all_pastes.iter().all(|paste| paste.id.as_deref() != Some(&file_name)) { + if let Err(err) = aws_service.delete_file(&file_name).await { + error!("Failed to delete invalid file {}: {}", file_name, err); + } else { + warn!("Deleted invalid file: {}", file_name); + } + } + } + } + + Ok(()) + } +} diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/BucketUtils.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/BucketUtils.kt deleted file mode 100644 index 522de61..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/BucketUtils.kt +++ /dev/null @@ -1,23 +0,0 @@ -package dev.loudbook.pastebook - -import io.github.bucket4j.Bandwidth -import io.github.bucket4j.Bucket -import io.github.bucket4j.Refill -import java.time.Duration - - -object BucketUtils { - fun getBucketPerSeconds(perSeconds: Long): Bucket { - val limit = Bandwidth.classic(perSeconds, Refill.greedy(perSeconds, Duration.ofSeconds(1))) - return Bucket.builder() - .addLimit(limit) - .build() - } - - fun getBucketPerMinutes(perMinutes: Long): Bucket { - val limit = Bandwidth.classic(perMinutes, Refill.greedy(perMinutes, Duration.ofMinutes(1))) - return Bucket.builder() - .addLimit(limit) - .build() - } -} \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/ContentScanner.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/ContentScanner.kt deleted file mode 100644 index 4721da5..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/ContentScanner.kt +++ /dev/null @@ -1,25 +0,0 @@ -package dev.loudbook.pastebook - -object ContentScanner { - fun scanContent(content: String): String { -/* val lines = content.split("\n").toMutableList() - - for ((index, line) in lines.withIndex()) { - val words = line.split(" ").toMutableList() - - for ((wordIndex, word) in words.withIndex()) { - if (InetAddressValidator.getInstance().isValidInet4Address(word)) { - words[wordIndex] = "***.***.***.***" - } else if (InetAddressValidator.getInstance().isValidInet6Address(word)) { - words[wordIndex] = "****:****:****:****:****:****:****:****" - } - } - - lines[index] = words.joinToString(" ") - } - - return lines.joinToString("\n")*/ - - return content - } -} \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/DeleteHandler.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/DeleteHandler.kt deleted file mode 100644 index 24f9a11..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/DeleteHandler.kt +++ /dev/null @@ -1,63 +0,0 @@ -package dev.loudbook.pastebook - -import dev.loudbook.pastebook.data.PastePrivateDTO -import dev.loudbook.pastebook.data.R2Service -import dev.loudbook.pastebook.mongo.PasteRepository -import jakarta.annotation.PostConstruct -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.stereotype.Component -import kotlin.concurrent.fixedRateTimer - -@Component -class DeleteHandler { - @Autowired - lateinit var r2Service: R2Service - - @Autowired - lateinit var pasteRepository: PasteRepository - - private val logger: Logger = LoggerFactory.getLogger(DeleteHandler::class.java) - - @PostConstruct - fun init() { - beginLoop() - } - - private final fun beginLoop() { - fixedRateTimer("timer", true, 1000, 1000 * 60 * 10) { - deleteFiles() - } - } - - private fun deleteFiles() { - val deletablePastes = mutableListOf() - val allPastes = mutableListOf() - - var index = 0 - - pasteRepository.findAllDTO().forEach { - val expires = it.expires - index++ - - allPastes.add(it) - - if (System.currentTimeMillis() > expires && expires != 0L) { - deletablePastes.add(it) - } - } - - for (paste in deletablePastes) { - pasteRepository.delete(paste) - paste.id?.let { r2Service.deleteFile(it) } ?: logger.error("Failed to delete paste; $paste") - } - - for (listFileName in r2Service.listFileNames()) { - if (allPastes.none{ it.id == listFileName}) { - r2Service.deleteFile(listFileName) - logger.warn("Deleted invalid file $listFileName") - } - } - } -} \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/IPUtils.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/IPUtils.kt deleted file mode 100644 index 5def367..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/IPUtils.kt +++ /dev/null @@ -1,19 +0,0 @@ -package dev.loudbook.pastebook - -import jakarta.servlet.http.HttpServletRequest - -object IPUtils { - fun getIPFromRequest(request: HttpServletRequest): String? { - var xRealIP = request.getHeader("Cf-Connecting-IP") - - if (xRealIP == null) { - xRealIP = request.getHeader("CF-Connecting-IPv6") - } - - if (xRealIP == null) { - return request.remoteAddr - } - - return xRealIP.split(",")[0] - } -} \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/PasteBookApplication.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/PasteBookApplication.kt deleted file mode 100644 index 8a42001..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/PasteBookApplication.kt +++ /dev/null @@ -1,14 +0,0 @@ -package dev.loudbook.pastebook - -import org.springframework.boot.SpringApplication -import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.data.mongodb.repository.config.EnableMongoRepositories - -@SpringBootApplication -@EnableMongoRepositories -class PasteBookApplication - -fun main(args: Array) { - val application = SpringApplication(PasteBookApplication::class.java) - application.run(*args) -} \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/config/Configuration.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/config/Configuration.kt deleted file mode 100644 index 7a39ce4..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/config/Configuration.kt +++ /dev/null @@ -1,11 +0,0 @@ -package dev.loudbook.pastebook.config - -import dev.loudbook.pastebook.DeleteHandler -import org.springframework.context.annotation.Bean -import org.springframework.stereotype.Component - -@Component -class Configuration { - @Bean - fun deleteHandler() = DeleteHandler() -} \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/config/WebConfig.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/config/WebConfig.kt deleted file mode 100644 index d8cb93a..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/config/WebConfig.kt +++ /dev/null @@ -1,13 +0,0 @@ -package dev.loudbook.pastebook.config -import org.springframework.context.annotation.Configuration -import org.springframework.web.servlet.config.annotation.CorsRegistry -import org.springframework.web.servlet.config.annotation.EnableWebMvc -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer - -@Configuration -@EnableWebMvc -class WebConfig : WebMvcConfigurer { - override fun addCorsMappings(registry: CorsRegistry) { - registry.addMapping("/**") - } -} \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/controllers/GetController.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/controllers/GetController.kt deleted file mode 100644 index 6239b0c..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/controllers/GetController.kt +++ /dev/null @@ -1,97 +0,0 @@ -package dev.loudbook.pastebook.controllers - -import com.google.gson.Gson -import dev.loudbook.pastebook.BucketUtils -import dev.loudbook.pastebook.data.R2Service -import dev.loudbook.pastebook.data.PastePrivateDTO -import dev.loudbook.pastebook.mongo.PasteRepository -import dev.loudbook.pastebook.mongo.UserService -import io.github.bucket4j.Bucket -import jakarta.servlet.http.HttpServletRequest -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.http.HttpHeaders -import org.springframework.http.MediaType -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.* -import java.io.ByteArrayOutputStream -import java.util.zip.GZIPOutputStream - -@RestController -class GetController { - @Autowired - lateinit var r2Service: R2Service - - @Autowired - lateinit var pasteRepository: PasteRepository - - @Autowired - lateinit var userService: UserService - - private val bucket: Bucket = BucketUtils.getBucketPerSeconds(4) - - @GetMapping("/get/{id}/metadata") - fun get(@PathVariable id: String, request: HttpServletRequest): ResponseEntity { - if (!userService.processRequest(request)) { - return ResponseEntity.status(403).body("Prohibited") - } - - if (!bucket.tryConsume(1)) { - return ResponseEntity.status(429).body("Rate limit exceeded") - } - - val paste: PastePrivateDTO = pasteRepository.findDTOByID(id) ?: return ResponseEntity.notFound().build() - - val json = Gson().toJson(userService.getUser(paste.creatorIP)?.toDTO()?.let { paste.toPublicDTO(it) }) ?: return ResponseEntity.notFound().build() - return ResponseEntity.ok().body(json) - } - - @GetMapping("/get/{id}/content") - fun getContent( - @RequestParam(required = false, defaultValue = "true") compress: Boolean, - @PathVariable id: String, - request: HttpServletRequest - ): ResponseEntity { - if (!userService.processRequest(request)) { - return ResponseEntity.status(403).body("Prohibited") - } - - if (!bucket.tryConsume(1)) { - return ResponseEntity.status(429).body(null) - } - - val headers = HttpHeaders() - - if (compress) { - headers.add("Content-Encoding", "gzip") - } else { - headers.add("Content-Type", "text/plain; charset=utf-8") - } - - val paste = r2Service.getFile(id) ?: return ResponseEntity.notFound().build() - val pasteData = paste.toByteArray() - - return if (compress) { - val compressed = compressData(pasteData) - ResponseEntity.ok() - .contentType(MediaType.TEXT_PLAIN) - .headers(headers) - .body(compressed) - } else { - ResponseEntity.ok() - .contentType(MediaType.TEXT_PLAIN) - .headers(headers) - .body(paste) - } - } - - private fun compressData(data: ByteArray): ByteArray { - val byteArrayOutputStream = ByteArrayOutputStream() - val gzipOutputStream = GZIPOutputStream(byteArrayOutputStream) - - gzipOutputStream.use { outputStream -> - outputStream.write(data) - } - - return byteArrayOutputStream.toByteArray() - } -} \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/controllers/UploadController.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/controllers/UploadController.kt deleted file mode 100644 index b4ec7e5..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/controllers/UploadController.kt +++ /dev/null @@ -1,89 +0,0 @@ -package dev.loudbook.pastebook.controllers - -import dev.loudbook.pastebook.BucketUtils -import dev.loudbook.pastebook.ContentScanner -import dev.loudbook.pastebook.IPUtils -import dev.loudbook.pastebook.data.PastePrivateDTO -import dev.loudbook.pastebook.data.R2Service -import dev.loudbook.pastebook.mongo.PasteRepository -import dev.loudbook.pastebook.mongo.UserService -import io.github.bucket4j.Bucket -import jakarta.servlet.http.HttpServletRequest -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.http.HttpHeaders -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.PostMapping -import org.springframework.web.bind.annotation.RequestBody -import org.springframework.web.bind.annotation.RestController - -@RestController -class UploadController { - @Autowired - lateinit var r2Service: R2Service - - @Autowired - lateinit var pasteRepository: PasteRepository - - @Autowired - lateinit var userService: UserService - - private val bucket: Bucket = BucketUtils.getBucketPerMinutes(4) - - @PostMapping(value = ["/upload"]) - fun upload(request: HttpServletRequest, @RequestBody body: String): ResponseEntity { - if (!userService.processRequest(request)) { - return ResponseEntity.status(403).body("Prohibited") - } - - if (!bucket.tryConsume(1)) { - return ResponseEntity.status(429).body("Rate limit exceeded") - } - - val header = HttpHeaders() - - val fileID = generateRandomString() - - val sinceTheEpoch = System.currentTimeMillis() - - val title = request.getHeader("title") ?: return ResponseEntity.badRequest().body("Title is required") - val reportBook = request.getHeader("reportBook")?.toBoolean() == true - val wrap = request.getHeader("wrap")?.toBoolean() == true - var expire = request.getHeader("expires")?.toLong() ?: (sinceTheEpoch + 8.64e+7).toLong() - - val hostDomain = request.getHeader("X-Domain-Name") - - if (expire < 60000) { - return ResponseEntity.badRequest().body("Expire time too short") - } - - if (expire < sinceTheEpoch) { - expire += sinceTheEpoch - } - - if (expire > (sinceTheEpoch + 2.765e+9)) { - return ResponseEntity.badRequest().body("Expire time too long") - } - - val filteredBody = ContentScanner.scanContent(body) - - val ip = IPUtils.getIPFromRequest(request) ?: return ResponseEntity.badRequest().body("Failed to get IP") - - val paste = PastePrivateDTO(fileID, title, sinceTheEpoch, reportBook, wrap, ip, expire) - - r2Service.uploadFile(fileID, filteredBody) - pasteRepository.save(paste) - - if (hostDomain != null) { - return ResponseEntity.ok().headers(header).body("https://$hostDomain/p/$fileID") - } - - return ResponseEntity.ok().headers(header).body(fileID) - } - - fun generateRandomString(length: Int = 5): String { - val chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - return (1..length) - .map { chars.random() } - .joinToString("") - } -} \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/data/PasteDTO.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/data/PasteDTO.kt deleted file mode 100644 index 28d24e8..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/data/PasteDTO.kt +++ /dev/null @@ -1,6 +0,0 @@ -package dev.loudbook.pastebook.data - -import org.springframework.data.annotation.Id - -@Suppress("unused") -class PasteDTO(@Id var id: String?, val user: UserDTO, val title: String, val created: Long, val reportBook: Boolean = false, val wrap: Boolean = false, val expiresAt: Long) \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/data/PastePrivateDTO.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/data/PastePrivateDTO.kt deleted file mode 100644 index 690dfcb..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/data/PastePrivateDTO.kt +++ /dev/null @@ -1,8 +0,0 @@ -package dev.loudbook.pastebook.data - -import org.springframework.data.annotation.Id - -@Suppress("unused") -data class PastePrivateDTO(@Id var id: String?, val title: String, val created: Long, val reportBook: Boolean = false, val wrap: Boolean = false, val creatorIP: String, val expires: Long){ - fun toPublicDTO(user: UserDTO) = PasteDTO(id, user, title, created, reportBook, wrap, expires) -} \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/data/R2Service.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/data/R2Service.kt deleted file mode 100644 index 07a330f..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/data/R2Service.kt +++ /dev/null @@ -1,72 +0,0 @@ -package dev.loudbook.pastebook.data - -import jakarta.annotation.PostConstruct -import org.springframework.beans.factory.annotation.Value -import org.springframework.stereotype.Service -import software.amazon.awssdk.auth.credentials.AwsBasicCredentials -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider -import software.amazon.awssdk.core.sync.RequestBody -import software.amazon.awssdk.regions.Region -import software.amazon.awssdk.services.s3.S3Client -import software.amazon.awssdk.services.s3.S3Configuration -import software.amazon.awssdk.services.s3.model.CreateBucketRequest -import software.amazon.awssdk.services.s3.model.GetObjectRequest -import software.amazon.awssdk.services.s3.model.ListObjectsRequest -import software.amazon.awssdk.services.s3.model.PutObjectRequest -import java.net.URI - -@Service -class R2Service { - private var amazonS3: S3Client? = null - - @Value("\${s3.accessKey}") - private val accessKey: String? = null - - @Value("\${s3.secretKey}") - private val secretKey: String? = null - - @Value("\${s3.url}") - private val url: String? = null - - @Value("\${s3.bucket}") - private val bucket: String? = null - - @PostConstruct - fun init() { - try { - amazonS3 = S3Client.builder() - .region(Region.US_EAST_1) - .credentialsProvider(AwsCredentialsProvider { AwsBasicCredentials.create(accessKey, secretKey) }) - .endpointOverride(URI.create(url!!)) - .serviceConfiguration(S3Configuration.builder() - .pathStyleAccessEnabled(true) - .build()) - .build() - - if (!amazonS3?.listBuckets()?.buckets()?.any { it.name() == bucket }!!) { - amazonS3?.createBucket(CreateBucketRequest.builder().bucket(bucket).build()) - } - } catch (e: Exception) { - e.printStackTrace() - } - } - - fun uploadFile(key: String, paste: String) { - amazonS3?.putObject(PutObjectRequest.builder().bucket(bucket).key(key).build(), RequestBody.fromString(paste)) - } - - fun deleteFile(key: String) { - amazonS3?.deleteObject { it.bucket(bucket).key(key) } - } - - fun getFile(key: String): String? { - val str = amazonS3?.getObject(GetObjectRequest.builder().bucket(bucket).key(key).build())?.readAllBytes() - ?.toString(Charsets.UTF_8) - - return str - } - - fun listFileNames(): List { - return amazonS3?.listObjects(ListObjectsRequest.builder().bucket(bucket).build())?.contents()?.map { it.key() } ?: emptyList() - } -} \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/data/User.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/data/User.kt deleted file mode 100644 index 1185c96..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/data/User.kt +++ /dev/null @@ -1,8 +0,0 @@ -package dev.loudbook.pastebook.data - -import org.springframework.data.annotation.Id - -data class User(@Id val ip: String, val id: String, val requests: Int, val lastVisit: Long, val banned: Boolean) { - fun incrementRequests() = User(ip, id, requests + 1, System.currentTimeMillis(), banned) - fun toDTO() = UserDTO(id) -} \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/data/UserDTO.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/data/UserDTO.kt deleted file mode 100644 index a4bf6c3..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/data/UserDTO.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.loudbook.pastebook.data - -data class UserDTO(val id: String) \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/MigrationHandler.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/MigrationHandler.kt deleted file mode 100644 index fce5770..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/MigrationHandler.kt +++ /dev/null @@ -1,63 +0,0 @@ -package dev.loudbook.pastebook.mongo - -import org.bson.Document -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.springframework.boot.CommandLineRunner -import org.springframework.data.mongodb.core.MongoTemplate -import org.springframework.data.mongodb.core.query.Criteria -import org.springframework.data.mongodb.core.query.Query -import org.springframework.data.mongodb.core.query.Update -import org.springframework.stereotype.Component -import java.util.UUID - -@Component -class MigrationHandler(private val mongoTemplate: MongoTemplate) : CommandLineRunner { - - private val logger: Logger = LoggerFactory.getLogger(MigrationHandler::class.java) - - override fun run(vararg args: String?) { - idMigration(mongoTemplate) - } - - fun idMigration(mongoTemplate: MongoTemplate) { - val migrationQuery = Query(Criteria.where("migration").`is`("fixMissingIds")) - val existingMigration = mongoTemplate.findOne(migrationQuery, MigrationRecord::class.java) - - if (existingMigration != null) { - logger.info("ID migration already completed.") - return - } - - logger.info("Beginning migration of missing IDs...") - - val users = mongoTemplate.findAll(Document::class.java, "users") - - var result = 0 - - users.forEach { - val id = it.getString("id") - if (id == null) { - val newId = UUID.randomUUID().toString() - val query = Query(Criteria.where("_id").`is`(it.getObjectId("_id"))) - val update = Update().set("id", newId) - mongoTemplate.updateFirst(query, update, "users") - logger.info("Fixed missing ID for user ${it.getString("ip")}") - - result++ - } - } - - - if (result > 0) { - logger.info("Fixed ${result} missing IDs.") - } else { - logger.info("No missing IDs found.") - } - - mongoTemplate.save(MigrationRecord("fixMissingIds")) - logger.info("ID migration complete.") - } -} - -data class MigrationRecord(val migration: String) diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/PasteRepository.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/PasteRepository.kt deleted file mode 100644 index b6fadf1..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/PasteRepository.kt +++ /dev/null @@ -1,13 +0,0 @@ -package dev.loudbook.pastebook.mongo - -import dev.loudbook.pastebook.data.PastePrivateDTO -import org.springframework.data.mongodb.repository.MongoRepository -import org.springframework.data.mongodb.repository.Query - -interface PasteRepository : MongoRepository { - @Query(value = "{}", fields = "{ 'content' : 0 }") - fun findAllDTO(): List - - @Query("{ 'id' : ?0 }", fields = "{ 'content' : 0 }") - fun findDTOByID(id: String): PastePrivateDTO? -} \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/UserService.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/UserService.kt deleted file mode 100644 index b13a00f..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/UserService.kt +++ /dev/null @@ -1,40 +0,0 @@ -package dev.loudbook.pastebook.mongo - -import dev.loudbook.pastebook.IPUtils -import dev.loudbook.pastebook.data.User -import jakarta.servlet.http.HttpServletRequest -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.stereotype.Service -import java.util.UUID - -@Service -class UserService { - @Autowired - private lateinit var usersRepository: UsersRepository - - fun incrementRequests(ip: String) { - val user = usersRepository.findByIp(ip) - if (user != null) { - val newUser = user.incrementRequests() - usersRepository.save(newUser) - } else { - val userID = UUID.randomUUID().toString() - usersRepository.save(User(ip, userID, 1, System.currentTimeMillis(), false)) - } - } - - fun processRequest(request: HttpServletRequest): Boolean { - val ip = IPUtils.getIPFromRequest(request) ?: return false - val user = usersRepository.findByIp(ip) - if (user != null && user.banned) { - return false - } - - incrementRequests(ip) - return true - } - - fun getUser(ip: String): User? { - return usersRepository.findByIp(ip) - } -} \ No newline at end of file diff --git a/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/UsersRepository.kt b/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/UsersRepository.kt deleted file mode 100644 index 36fc1cd..0000000 --- a/backend/src/main/kotlin/dev/loudbook/pastebook/mongo/UsersRepository.kt +++ /dev/null @@ -1,10 +0,0 @@ -package dev.loudbook.pastebook.mongo - -import dev.loudbook.pastebook.data.User -import org.springframework.data.mongodb.repository.MongoRepository -import org.springframework.data.mongodb.repository.Query - -interface UsersRepository : MongoRepository { - @Query("{ 'ip' : ?0 }") - fun findByIp(ip: String): User? -} \ No newline at end of file diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml deleted file mode 100644 index 95edac5..0000000 --- a/backend/src/main/resources/application.yml +++ /dev/null @@ -1,15 +0,0 @@ -server: - port: 8080 - -spring: - application: - name: PasteBook - data: - mongodb: - uri: ${SPRING_DATA_MONGODB_URI} - -s3: - url: ${S3_ENDPOINT} - accessKey: ${S3_ACCESS_KEY_ID} - secretKey: ${S3_SECRET_ACCESS_KEY} - bucket: ${S3_BUCKET} \ No newline at end of file diff --git a/backend/src/models/mod.rs b/backend/src/models/mod.rs new file mode 100644 index 0000000..5d536bd --- /dev/null +++ b/backend/src/models/mod.rs @@ -0,0 +1,2 @@ +pub mod user; +pub mod paste; \ No newline at end of file diff --git a/backend/src/models/paste.rs b/backend/src/models/paste.rs new file mode 100644 index 0000000..dae7a76 --- /dev/null +++ b/backend/src/models/paste.rs @@ -0,0 +1,38 @@ +use serde::{Deserialize, Serialize}; +use crate::models::user::UserDTO; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Paste { + pub id: Option, + pub title: String, + pub created: u64, + pub report_book: bool, + pub wrap: bool, + pub creator_ip: String, + pub expires: u64, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct PasteDTO { + pub id: Option, + pub user: UserDTO, + pub title: String, + pub created: u64, + pub report_book: bool, + pub wrap: bool, + pub expires: u64, +} + +impl Paste { + pub fn to_public_dto(&self, user: UserDTO) -> PasteDTO { + PasteDTO { + id: self.id.clone(), + user, + title: self.title.clone(), + created: self.created, + report_book: self.report_book, + wrap: self.wrap, + expires: self.expires, + } + } +} diff --git a/backend/src/models/user.rs b/backend/src/models/user.rs new file mode 100644 index 0000000..66580a6 --- /dev/null +++ b/backend/src/models/user.rs @@ -0,0 +1,29 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct User { + pub ip: String, + pub id: String, + pub requests: u64, + pub created_at: i64, + pub banned: bool, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct UserDTO { + pub id: String, + pub requests: u64, + pub created_at: i64, + pub banned: bool, +} + +impl User { + pub fn to_dto(&self) -> UserDTO { + UserDTO { + id: self.id.clone(), + requests: self.requests, + created_at: self.created_at, + banned: self.banned, + } + } +} \ No newline at end of file diff --git a/backend/src/mongodb_service.rs b/backend/src/mongodb_service.rs new file mode 100644 index 0000000..50f4f2f --- /dev/null +++ b/backend/src/mongodb_service.rs @@ -0,0 +1,80 @@ +use mongodb::bson::{doc, uuid}; +use mongodb::{Client, Collection, Cursor}; +use mongodb::options::ClientOptions; +use crate::models::paste::Paste; +use crate::models::user::User; +use crate::mongoresult::MongoResult; + +pub struct MongoService { + client: Client, + user_collection: Collection, + paste_collection: Collection, +} + +impl MongoService { + pub async fn new(uri: &str, db_name: &str) -> MongoResult { + let client_options = ClientOptions::parse(uri).await?; + let client = Client::with_options(client_options)?; + + let database = client.database(db_name); + let user_collection = database.collection::("users"); + let paste_collection = database.collection::("pastes"); + + Ok(Self { + client, + user_collection, + paste_collection, + }) + } + + pub async fn increment_requests(&self, ip: &str) -> MongoResult<()> { + let filter = doc! { "ip": ip }; + let update = doc! { + "$inc": { "request_count": 1 }, + "$setOnInsert": { + "user_id": uuid::Uuid::new().to_string(), + "created_at": chrono::Utc::now().timestamp_millis(), + "banned": false + } + }; + + self.user_collection.update_one(filter, update).upsert(true).await?; + Ok(()) + } + + pub async fn put_paste(&self, paste: Paste) -> MongoResult<()> { + self.paste_collection.insert_one(paste).await?; + Ok(()) + } + + pub async fn delete_paste(&self, id: &str) -> MongoResult<()> { + self.paste_collection.delete_one(doc! { "id": id }).await?; + Ok(()) + } + + pub async fn is_user_banned(&self, ip: &str) -> MongoResult { + if let Some(user) = self.user_collection.find_one(doc! { "ip": ip }).await? { + Ok(user.banned) + } else { + Ok(false) + } + } + + pub async fn get_user(&self, ip: &str) -> MongoResult> { + let user = self.user_collection.find_one(doc! { "ip": ip }).await?; + Ok(user) + } + + pub async fn get_paste_metadata(&self, id: &str) -> MongoResult> { + let paste = self.paste_collection.find_one(doc! { "id": id }).await?; + Ok(paste) + } + + pub async fn get_all_pastes_metadata(&self) -> MongoResult> { + let cursor = self + .paste_collection + .find(doc! {}) + .await?; + Ok(cursor) + } +} \ No newline at end of file diff --git a/backend/src/mongoresult.rs b/backend/src/mongoresult.rs new file mode 100644 index 0000000..434e7c6 --- /dev/null +++ b/backend/src/mongoresult.rs @@ -0,0 +1,3 @@ +use mongodb::error::Error; + +pub type MongoResult = Result; \ No newline at end of file diff --git a/backend/src/test/kotlin/dev/loudbook/pastebook/pastebook/PasteBookApplicationTests.kt b/backend/src/test/kotlin/dev/loudbook/pastebook/pastebook/PasteBookApplicationTests.kt deleted file mode 100644 index d421c14..0000000 --- a/backend/src/test/kotlin/dev/loudbook/pastebook/pastebook/PasteBookApplicationTests.kt +++ /dev/null @@ -1,13 +0,0 @@ -package dev.loudbook.pastebook.pastebook - -import org.junit.jupiter.api.Test -import org.springframework.boot.test.context.SpringBootTest - -@SpringBootTest -class PasteBookApplicationTests { - - @Test - fun contextLoads() { - } - -} diff --git a/backend/src/utils/iputils.rs b/backend/src/utils/iputils.rs new file mode 100644 index 0000000..017265f --- /dev/null +++ b/backend/src/utils/iputils.rs @@ -0,0 +1,22 @@ +use actix_web::HttpRequest; + +pub struct IPUtils; + +impl IPUtils { + pub fn get_ip_from_request(req: &HttpRequest) -> Option { + if let Some(ip) = req.headers().get("Cf-Connecting-IP").and_then(|v| v.to_str().ok()) { + return Some(Self::extract_first_ip(ip)); + } + + if let Some(ip) = req.headers().get("CF-Connecting-IPv6").and_then(|v| v.to_str().ok()) { + return Some(Self::extract_first_ip(ip)); + } + + req.peer_addr() + .map(|addr| addr.ip().to_string()) + } + + fn extract_first_ip(ip_list: &str) -> String { + ip_list.split(',').next().unwrap_or("").trim().to_string() + } +} diff --git a/backend/src/utils/mod.rs b/backend/src/utils/mod.rs new file mode 100644 index 0000000..e38bd47 --- /dev/null +++ b/backend/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod iputils; \ No newline at end of file From e229516d8b4d94e358c2144c8b361966abea43df Mon Sep 17 00:00:00 2001 From: Loudbook Date: Mon, 9 Dec 2024 20:22:40 -0500 Subject: [PATCH 140/188] Cargo --- backend/Cargo.lock | 3233 ++++++++++++++++++++++++++++++++++++++++++++ backend/Cargo.toml | 19 + 2 files changed, 3252 insertions(+) create mode 100644 backend/Cargo.lock create mode 100644 backend/Cargo.toml diff --git a/backend/Cargo.lock b/backend/Cargo.lock new file mode 100644 index 0000000..862ef2b --- /dev/null +++ b/backend/Cargo.lock @@ -0,0 +1,3233 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "actix-codec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" +dependencies = [ + "bitflags 2.6.0", + "bytes", + "futures-core", + "futures-sink", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-http" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d48f96fc3003717aeb9856ca3d02a8c7de502667ad76eeacd830b48d2e91fac4" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "ahash", + "base64 0.22.1", + "bitflags 2.6.0", + "brotli", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "futures-core", + "h2", + "http 0.2.12", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite", + "rand", + "sha1", + "smallvec", + "tokio", + "tokio-util", + "tracing", + "zstd", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote", + "syn 2.0.90", +] + +[[package]] +name = "actix-router" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" +dependencies = [ + "bytestring", + "cfg-if", + "http 0.2.12", + "regex", + "regex-lite", + "serde", + "tracing", +] + +[[package]] +name = "actix-rt" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca2549781d8dd6d75c40cf6b6051260a2cc2f3c62343d761a969a0640646894" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +dependencies = [ + "futures-core", + "paste", + "pin-project-lite", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9180d76e5cc7ccbc4d60a506f2c727730b154010262df5b910eb17dbe4b8cb38" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen", + "ahash", + "bytes", + "bytestring", + "cfg-if", + "cookie", + "derive_more", + "encoding_rs", + "futures-core", + "futures-util", + "impl-more", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex", + "regex-lite", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2", + "time", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f591380e2e68490b5dfaf1dd1aa0ebe78d84ba7067078512b4ea6e4492d622b8" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "aws-credential-types" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60e8f6b615cb5fc60a98132268508ad104310f0cfb25a1c22eee76efdf9154da" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "zeroize", +] + +[[package]] +name = "aws-runtime" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5ac934720fbb46206292d2c75b57e67acfc56fe7dfd34fb9a02334af08409ea" +dependencies = [ + "aws-credential-types", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand", + "http 0.2.12", + "http-body 0.4.6", + "once_cell", + "percent-encoding", + "pin-project-lite", + "tracing", + "uuid", +] + +[[package]] +name = "aws-sdk-s3" +version = "1.65.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3ba2c5c0f2618937ce3d4a5ad574b86775576fa24006bcb3128c6e2cbf3c34e" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-checksums", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "bytes", + "fastrand", + "hex", + "hmac", + "http 0.2.12", + "http-body 0.4.6", + "lru", + "once_cell", + "percent-encoding", + "regex-lite", + "sha2", + "tracing", + "url", +] + +[[package]] +name = "aws-sigv4" +version = "1.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d3820e0c08d0737872ff3c7c1f21ebbb6693d832312d6152bf18ef50a5471c2" +dependencies = [ + "aws-credential-types", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "crypto-bigint 0.5.5", + "form_urlencoded", + "hex", + "hmac", + "http 0.2.12", + "http 1.2.0", + "once_cell", + "p256", + "percent-encoding", + "ring", + "sha2", + "subtle", + "time", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-smithy-async" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62220bc6e97f946ddd51b5f1361f78996e704677afc518a4ff66b7a72ea1378c" +dependencies = [ + "futures-util", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "aws-smithy-checksums" +version = "0.60.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1a71073fca26775c8b5189175ea8863afb1c9ea2cceb02a5de5ad9dfbaa795" +dependencies = [ + "aws-smithy-http", + "aws-smithy-types", + "bytes", + "crc32c", + "crc32fast", + "hex", + "http 0.2.12", + "http-body 0.4.6", + "md-5", + "pin-project-lite", + "sha1", + "sha2", + "tracing", +] + +[[package]] +name = "aws-smithy-eventstream" +version = "0.60.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef7d0a272725f87e51ba2bf89f8c21e4df61b9e49ae1ac367a6d69916ef7c90" +dependencies = [ + "aws-smithy-types", + "bytes", + "crc32fast", +] + +[[package]] +name = "aws-smithy-http" +version = "0.60.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8bc3e8fdc6b8d07d976e301c02fe553f72a39b7a9fea820e023268467d7ab6" +dependencies = [ + "aws-smithy-eventstream", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http-body 0.4.6", + "once_cell", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", +] + +[[package]] +name = "aws-smithy-json" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4e69cc50921eb913c6b662f8d909131bb3e6ad6cb6090d3a39b66fc5c52095" +dependencies = [ + "aws-smithy-types", +] + +[[package]] +name = "aws-smithy-runtime" +version = "1.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f20685047ca9d6f17b994a07f629c813f08b5bce65523e47124879e60103d45" +dependencies = [ + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "fastrand", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "http-body 1.0.1", + "httparse", + "hyper", + "hyper-rustls", + "once_cell", + "pin-project-lite", + "pin-utils", + "rustls", + "tokio", + "tracing", +] + +[[package]] +name = "aws-smithy-runtime-api" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92165296a47a812b267b4f41032ff8069ab7ff783696d217f0994a0d7ab585cd" +dependencies = [ + "aws-smithy-async", + "aws-smithy-types", + "bytes", + "http 0.2.12", + "http 1.2.0", + "pin-project-lite", + "tokio", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-smithy-types" +version = "1.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fbd94a32b3a7d55d3806fe27d98d3ad393050439dd05eb53ece36ec5e3d3510" +dependencies = [ + "base64-simd", + "bytes", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http 1.2.0", + "http-body 0.4.6", + "http-body 1.0.1", + "http-body-util", + "itoa", + "num-integer", + "pin-project-lite", + "pin-utils", + "ryu", + "serde", + "time", + "tokio", + "tokio-util", +] + +[[package]] +name = "aws-smithy-xml" +version = "0.60.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab0b0166827aa700d3dc519f72f8b3a91c35d0b8d042dc5d643a91e6f80648fc" +dependencies = [ + "xmlparser", +] + +[[package]] +name = "aws-types" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5221b91b3e441e6675310829fd8984801b772cb1546ef6c0e54dec9f1ac13fef" +dependencies = [ + "aws-credential-types", + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "rustc_version", + "tracing", +] + +[[package]] +name = "backend" +version = "0.1.0" +dependencies = [ + "actix-web", + "anyhow", + "aws-credential-types", + "aws-sdk-s3", + "chrono", + "dotenv", + "flate2", + "futures-util", + "log", + "mongodb", + "rand", + "serde", + "tokio", +] + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "brotli" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bson" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068208f2b6fcfa27a7f1ee37488d2bb8ba2640f68f5475d08e1d9130696aba59" +dependencies = [ + "ahash", + "base64 0.13.1", + "bitvec", + "hex", + "indexmap 2.7.0", + "js-sys", + "once_cell", + "rand", + "serde", + "serde_bytes", + "serde_json", + "time", + "uuid", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" + +[[package]] +name = "bytes-utils" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" +dependencies = [ + "bytes", + "either", +] + +[[package]] +name = "bytestring" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" +dependencies = [ + "bytes", +] + +[[package]] +name = "cc" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.6", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32c" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a47af21622d091a8f0fb295b88bc886ac74efcc613efc19f5d0b21de5c89e47" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.90", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.90", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct", + "crypto-bigint 0.4.9", + "der", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "flate2" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.7.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hickory-proto" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.2.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "impl-more" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae21c3177a27788957044151cc2800043d127acaa460a47ebb9b84dfa2c6aa0" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", + "serde", +] + +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + +[[package]] +name = "libc" +version = "0.2.168" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[package]] +name = "local-channel" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" +dependencies = [ + "futures-core", + "futures-sink", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.2", +] + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "mongodb" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c857d71f918b38221baf2fdff7207fec9984b4504901544772b1edf0302d669f" +dependencies = [ + "async-trait", + "base64 0.13.1", + "bitflags 1.3.2", + "bson", + "chrono", + "derivative", + "derive_more", + "futures-core", + "futures-executor", + "futures-io", + "futures-util", + "hex", + "hickory-proto", + "hickory-resolver", + "hmac", + "md-5", + "mongodb-internal-macros", + "once_cell", + "pbkdf2", + "percent-encoding", + "rand", + "rustc_version_runtime", + "rustls", + "rustls-pemfile", + "serde", + "serde_bytes", + "serde_with", + "sha-1", + "sha2", + "socket2", + "stringprep", + "strsim", + "take_mut", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-util", + "typed-builder", + "uuid", + "webpki-roots", +] + +[[package]] +name = "mongodb-internal-macros" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a6dbc533e93429a71c44a14c04547ac783b56d3f22e6c4f12b1b994cf93844e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "outref" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" + +[[package]] +name = "p256" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" +dependencies = [ + "ecdsa", + "elliptic-curve", + "sha2", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint 0.4.9", + "hmac", + "zeroize", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustc_version_runtime" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd18cd2bae1820af0b6ad5e54f4a51d0f3fcc53b05f845675074efcc7af071d" +dependencies = [ + "rustc_version", + "semver", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "serde_json" +version = "1.0.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +dependencies = [ + "indexmap 2.7.0", + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.7.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typed-builder" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89851716b67b937e393b3daa8423e67ddfc4bbbf1654bcf05488e95e0828db0c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna 1.0.3", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.90", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/backend/Cargo.toml b/backend/Cargo.toml new file mode 100644 index 0000000..68a28d5 --- /dev/null +++ b/backend/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "backend" +version = "0.1.0" +edition = "2024" + +[dependencies] +actix-web = "4" +mongodb = "3.1.0" +aws-sdk-s3 = { version = "1.65.0" } +tokio = { version = "1", features = ["full"] } +anyhow = "1.0.94" +serde = { version = "1.0.215", features = ["derive"] } +flate2 = "1.0.35" +chrono = "0.4.39" +rand = "0.8.5" +log = "0.4.22" +dotenv = "0.15" +futures-util = "0.3.31" +aws-credential-types = { version = "1.2.1", features = ["hardcoded-credentials"] } \ No newline at end of file From 758807a4915adb9cdbe4d1640872775a6c3efc81 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 14:32:57 -0500 Subject: [PATCH 141/188] Formatting --- backend/Cargo.lock | 97 ++++++++++++++++++++++++++++++++++ backend/Cargo.toml | 5 +- backend/Dockerfile | 10 ++++ backend/src/aws_service.rs | 22 ++++++-- backend/src/main.rs | 72 +++++++++++++++++++++++++ backend/src/mongodb_service.rs | 5 +- 6 files changed, 203 insertions(+), 8 deletions(-) create mode 100644 backend/Dockerfile create mode 100644 backend/src/main.rs diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 862ef2b..a02456d 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -258,6 +258,55 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + [[package]] name = "anyhow" version = "1.0.94" @@ -558,6 +607,7 @@ dependencies = [ "aws-sdk-s3", "chrono", "dotenv", + "env_logger", "flate2", "futures-util", "log", @@ -766,6 +816,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + [[package]] name = "const-oid" version = "0.9.6" @@ -1036,6 +1092,29 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1385,6 +1464,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.31" @@ -1649,6 +1734,12 @@ version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" version = "1.0.14" @@ -2791,6 +2882,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.11.0" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 68a28d5..2aeaffd 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "backend" version = "0.1.0" -edition = "2024" +edition = "2021" [dependencies] actix-web = "4" @@ -16,4 +16,5 @@ rand = "0.8.5" log = "0.4.22" dotenv = "0.15" futures-util = "0.3.31" -aws-credential-types = { version = "1.2.1", features = ["hardcoded-credentials"] } \ No newline at end of file +aws-credential-types = { version = "1.2.1", features = ["hardcoded-credentials"] } +env_logger = "0.11.5" \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..ddeb490 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,10 @@ +FROM rust:latest + +COPY ./ ./ + +RUN cargo build + +RUN cp ./target/debug/backend ./ +RUN rm -rf ./src ./Cargo.toml ./Cargo.lock ./target + +CMD ["./backend"] diff --git a/backend/src/aws_service.rs b/backend/src/aws_service.rs index 50c02d9..2126f9b 100644 --- a/backend/src/aws_service.rs +++ b/backend/src/aws_service.rs @@ -10,18 +10,23 @@ pub struct AWSService { impl AWSService { pub async fn new(endpoint: &str, bucket_name: &str, access_key: &str, secret_key: &str) -> Result { + println!("Connecting to AWS S3..."); let region = Region::new("auto"); let credentials = Credentials::from_keys(access_key, secret_key, None); let shared_credentials = SharedCredentialsProvider::new(credentials); let config = Config::builder() + .force_path_style(true) .region(region) .credentials_provider(shared_credentials) .endpoint_url(endpoint) + .behavior_version_latest() .build(); let client = Client::from_conf(config); + println!("Connected to AWS S3"); + Ok(Self { client, bucket_name: bucket_name.to_string(), @@ -29,7 +34,7 @@ impl AWSService { } pub async fn get_file(&self, key: &str) -> Result> { - let resp = self + let response = self .client .get_object() .bucket(&self.bucket_name) @@ -37,7 +42,7 @@ impl AWSService { .send() .await?; - let data = resp.body.collect().await?; + let data = response.body.collect().await?; Ok(data.into_bytes().to_vec()) } @@ -63,7 +68,7 @@ impl AWSService { } pub async fn list_files(&self) -> Result> { - let resp = self + let response = self .client .list_objects_v2() .bucket(&self.bucket_name) @@ -71,7 +76,7 @@ impl AWSService { .await?; let mut keys = Vec::new(); - for object in resp.contents.unwrap_or_default() { + for object in response.contents.unwrap_or_default() { if let Some(key) = object.key { keys.push(key); } @@ -79,4 +84,13 @@ impl AWSService { Ok(keys) } + + pub async fn create_bucket(&self, bucket_name: &str) -> Result<()> { + self.client + .create_bucket() + .bucket(bucket_name) + .send() + .await?; + Ok(()) + } } diff --git a/backend/src/main.rs b/backend/src/main.rs new file mode 100644 index 0000000..084088a --- /dev/null +++ b/backend/src/main.rs @@ -0,0 +1,72 @@ +mod aws_service; +mod mongodb_service; +mod models; +mod controllers; +mod mongoresult; +mod utils; +mod delete_service; + +use crate::aws_service::AWSService; +use crate::controllers::get_controller::{get_content_handler, get_metadata_handler}; +use crate::controllers::upload_controller::upload_handler; +use crate::delete_service::DeleteHandler; +use crate::mongodb_service::MongoService; +use actix_web::{web, App, HttpResponse, HttpServer, Responder}; +use dotenv::dotenv; +use std::env; +use std::sync::Arc; + +#[actix_web::main] +async fn main() -> std::io::Result<()> { + env::set_var("RUST_LOG", "debug"); + env_logger::init(); + dotenv().ok(); + + let database_url = env::var("S3_ENDPOINT").expect("S3_ENDPOINT must be set"); + let aws_access_key = env::var("S3_ACCESS_KEY_ID").expect("S3_ACCESS_KEY_ID must be set"); + let aws_secret_key = env::var("S3_SECRET_ACCESS_KEY").expect("S3_SECRET_ACCESS_KEY must be set"); + let bucket_name = env::var("S3_BUCKET").expect("S3_BUCKET must be set"); + let mongo_url = env::var("SPRING_DATA_MONGODB_URI").expect("SPRING_DATA_MONGODB_URI must be set"); + + let aws_service = Arc::new( + AWSService::new( + &database_url, + &bucket_name, + &aws_access_key, + &aws_secret_key + ) + .await + .expect("Failed to initialize AWSService"), + ); + + aws_service.create_bucket(&bucket_name).await.expect("Failed to create bucket"); + + let mongo_service = Arc::new( + MongoService::new( + &mongo_url, + "pastebook" + ) + .await + .expect("Failed to initialize MongoService") + ); + + let delete_handler = DeleteHandler::new(Arc::clone(&aws_service), Arc::clone(&mongo_service)); + delete_handler.start_delete_loop(); + + HttpServer::new(move || { + App::new() + .app_data(web::Data::new(Arc::clone(&aws_service))) + .app_data(web::Data::new(Arc::clone(&mongo_service))) + .route("/get/{id}/content", web::get().to(get_content_handler)) + .route("/get/{id}/metadata", web::get().to(get_metadata_handler)) + .route("/upload", web::post().to(upload_handler)) + }) + .bind(("0.0.0.0", 8080))? + .run() + .await +} + +async fn health_check() -> impl Responder { + println!("Health check"); + HttpResponse::Ok().body("OK") +} \ No newline at end of file diff --git a/backend/src/mongodb_service.rs b/backend/src/mongodb_service.rs index 50f4f2f..2d44378 100644 --- a/backend/src/mongodb_service.rs +++ b/backend/src/mongodb_service.rs @@ -6,13 +6,13 @@ use crate::models::user::User; use crate::mongoresult::MongoResult; pub struct MongoService { - client: Client, user_collection: Collection, paste_collection: Collection, } impl MongoService { pub async fn new(uri: &str, db_name: &str) -> MongoResult { + println!("Connecting to MongoDB..."); let client_options = ClientOptions::parse(uri).await?; let client = Client::with_options(client_options)?; @@ -20,8 +20,9 @@ impl MongoService { let user_collection = database.collection::("users"); let paste_collection = database.collection::("pastes"); + println!("Connected to MongoDB"); + Ok(Self { - client, user_collection, paste_collection, }) From faadc29e031823d97db6e57315f33caecc77d2eb Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 16:46:03 -0500 Subject: [PATCH 142/188] Fixes --- backend/Dockerfile | 13 +++++++------ backend/src/aws_service.rs | 4 ++++ backend/src/controllers/upload_controller.rs | 4 +++- backend/src/delete_service.rs | 8 +++----- backend/src/main.rs | 1 - backend/src/models/paste.rs | 4 ++-- backend/src/mongodb_service.rs | 4 ++-- 7 files changed, 21 insertions(+), 17 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index ddeb490..06750c7 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,10 +1,11 @@ -FROM rust:latest - -COPY ./ ./ +FROM rust:latest as builder +COPY ./Cargo.toml ./Cargo.lock ./ +COPY ./src ./src RUN cargo build -RUN cp ./target/debug/backend ./ -RUN rm -rf ./src ./Cargo.toml ./Cargo.lock ./target +FROM rust:latest + +COPY --from=builder target/debug/backend /usr/local/bin/backend -CMD ["./backend"] +CMD ["/usr/local/bin/backend"] \ No newline at end of file diff --git a/backend/src/aws_service.rs b/backend/src/aws_service.rs index 2126f9b..127c9ba 100644 --- a/backend/src/aws_service.rs +++ b/backend/src/aws_service.rs @@ -86,6 +86,10 @@ impl AWSService { } pub async fn create_bucket(&self, bucket_name: &str) -> Result<()> { + if self.client.head_bucket().bucket(bucket_name).send().await.is_ok() { + return Ok(()); + } + self.client .create_bucket() .bucket(bucket_name) diff --git a/backend/src/controllers/upload_controller.rs b/backend/src/controllers/upload_controller.rs index 1edc330..61ed386 100644 --- a/backend/src/controllers/upload_controller.rs +++ b/backend/src/controllers/upload_controller.rs @@ -63,7 +63,7 @@ pub async fn upload_handler( let file_id = generate_random_string(5); let paste = Paste { - id: Some(file_id.clone()), + id: file_id.clone(), title: title.to_string(), created: since_the_epoch, report_book, @@ -79,6 +79,8 @@ pub async fn upload_handler( return HttpResponse::InternalServerError().body(format!("Failed to save to database: {:?}", e)); } + mongo_service.increment_requests(&ip).await.expect("Failed to increment requests"); + let host_domain = req .headers() .get("X-Domain-Name") diff --git a/backend/src/delete_service.rs b/backend/src/delete_service.rs index c101f21..c314b85 100644 --- a/backend/src/delete_service.rs +++ b/backend/src/delete_service.rs @@ -60,22 +60,20 @@ impl DeleteHandler { } for paste in &deletable_pastes { - let paste_id = paste.id.as_deref().unwrap_or_default(); + let paste_id = &paste.id; if let Err(err) = mongo_service.delete_paste(paste_id).await { error!("Failed to delete paste from database: {:?}", err); } - if let Some(id) = &paste.id { + if let id = &paste.id { if let Err(err) = mongo_service.delete_paste(id).await { error!("Failed to delete paste file: {}", err); } - } else { - error!("Paste ID is missing for: {:?}", paste); } } if let Ok(file_names) = aws_service.list_files().await { for file_name in file_names { - if all_pastes.iter().all(|paste| paste.id.as_deref() != Some(&file_name)) { + if all_pastes.iter().all(|paste| &paste.id != &file_name) { if let Err(err) = aws_service.delete_file(&file_name).await { error!("Failed to delete invalid file {}: {}", file_name, err); } else { diff --git a/backend/src/main.rs b/backend/src/main.rs index 084088a..cf77410 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -18,7 +18,6 @@ use std::sync::Arc; #[actix_web::main] async fn main() -> std::io::Result<()> { - env::set_var("RUST_LOG", "debug"); env_logger::init(); dotenv().ok(); diff --git a/backend/src/models/paste.rs b/backend/src/models/paste.rs index dae7a76..2786c4d 100644 --- a/backend/src/models/paste.rs +++ b/backend/src/models/paste.rs @@ -3,7 +3,7 @@ use crate::models::user::UserDTO; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Paste { - pub id: Option, + pub id: String, pub title: String, pub created: u64, pub report_book: bool, @@ -14,7 +14,7 @@ pub struct Paste { #[derive(Debug, Serialize, Deserialize, Clone)] pub struct PasteDTO { - pub id: Option, + pub id: String, pub user: UserDTO, pub title: String, pub created: u64, diff --git a/backend/src/mongodb_service.rs b/backend/src/mongodb_service.rs index 2d44378..db2e1cc 100644 --- a/backend/src/mongodb_service.rs +++ b/backend/src/mongodb_service.rs @@ -31,9 +31,9 @@ impl MongoService { pub async fn increment_requests(&self, ip: &str) -> MongoResult<()> { let filter = doc! { "ip": ip }; let update = doc! { - "$inc": { "request_count": 1 }, + "$inc": { "requests": 1 }, "$setOnInsert": { - "user_id": uuid::Uuid::new().to_string(), + "id": uuid::Uuid::new().to_string(), "created_at": chrono::Utc::now().timestamp_millis(), "banned": false } From 8292dc81569c82a194b8197ef1f37cc50ec385cd Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 16:53:24 -0500 Subject: [PATCH 143/188] Update docker-compose.yml --- docker-compose.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 24b1aa6..1139491 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,8 +11,8 @@ services: - S3_BUCKET=pastebook - S3_ENDPOINT=http://minio:9000 depends_on: - - mongo - - minio + minio: + condition: service_healthy networks: - pastebook-network @@ -43,7 +43,7 @@ services: networks: - pastebook-network pull_policy: always - + minio: image: quay.io/minio/minio:latest container_name: minio @@ -60,7 +60,12 @@ services: aliases: - pastebook.minio pull_policy: always - + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 2s + timeout: 2s + retries: 5 + volumes: mongo-data: minio-data: From 0eadec5f1769b442a3ae34b5f2cb0ad47ed22911 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 16:55:21 -0500 Subject: [PATCH 144/188] Update build-and-deploy.yml --- .github/workflows/build-and-deploy.yml | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 58d0850..97d3596 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -7,6 +7,7 @@ on: - backend/** branches: - master + - dev jobs: build: @@ -45,6 +46,19 @@ jobs: id: get_commit_hash run: echo "hash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + - name: Set Docker Tags + id: set_tags + run: | + if [ "${{ github.ref_name }}" == "master" ]; then + echo "tag=latest" >> $GITHUB_ENV + elif [ "${{ github.ref_name }}" == "dev" ]; then + echo "tag=dev" >> $GITHUB_ENV + else + echo "Unknown branch: ${{ github.ref_name }}" + exit 1 + fi + echo "branch_tag=${{ env.tag }}" >> $GITHUB_ENV + - name: Build and push frontend Docker image to GHCR uses: docker/build-push-action@v3 with: @@ -54,7 +68,7 @@ jobs: COMMIT_HASH=${{ env.hash }} push: true tags: | - ghcr.io/loudbooks/pastebook-frontend:latest + ghcr.io/loudbooks/pastebook-frontend:${{ env.branch_tag }} ghcr.io/loudbooks/pastebook-frontend:${{ env.hash }} - name: Build and push backend Docker image to GHCR @@ -64,7 +78,7 @@ jobs: file: ./backend/Dockerfile push: true tags: | - ghcr.io/loudbooks/pastebook-backend:latest + ghcr.io/loudbooks/pastebook-backend:${{ env.branch_tag }} ghcr.io/loudbooks/pastebook-backend:${{ env.hash }} - name: Log in to Docker Hub @@ -82,7 +96,7 @@ jobs: file: ./frontend/Dockerfile push: true tags: | - ${{ secrets.DOCKER_USERNAME }}/pastebook-frontend:latest + ${{ secrets.DOCKER_USERNAME }}/pastebook-frontend:${{ env.branch_tag }} ${{ secrets.DOCKER_USERNAME }}/pastebook-frontend:${{ env.hash }} - name: Build and push backend Docker image to Docker Hub @@ -92,5 +106,5 @@ jobs: file: ./backend/Dockerfile push: true tags: | - ${{ secrets.DOCKER_USERNAME }}/pastebook-backend:latest + ${{ secrets.DOCKER_USERNAME }}/pastebook-backend:${{ env.branch_tag }} ${{ secrets.DOCKER_USERNAME }}/pastebook-backend:${{ env.hash }} From 8433a3e3e2940d11260e9936364ccb4c3e8bae6b Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 16:56:14 -0500 Subject: [PATCH 145/188] CORS --- backend/src/main.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/src/main.rs b/backend/src/main.rs index cf77410..f51f9f8 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -15,6 +15,7 @@ use actix_web::{web, App, HttpResponse, HttpServer, Responder}; use dotenv::dotenv; use std::env; use std::sync::Arc; +use aws_sdk_s3::types::builders::CorsRuleBuilder; #[actix_web::main] async fn main() -> std::io::Result<()> { @@ -52,8 +53,14 @@ async fn main() -> std::io::Result<()> { let delete_handler = DeleteHandler::new(Arc::clone(&aws_service), Arc::clone(&mongo_service)); delete_handler.start_delete_loop(); + let cors = CorsRuleBuilder::default() + .allowed_origins(vec!["*"]) + .allowed_methods(vec!["GET", "POST"]) + .allowed_headers(vec!["*"]) + .build(); + HttpServer::new(move || { - App::new() + App::new().wrap(cors) .app_data(web::Data::new(Arc::clone(&aws_service))) .app_data(web::Data::new(Arc::clone(&mongo_service))) .route("/get/{id}/content", web::get().to(get_content_handler)) From 41d4e0651f6a9b8bbd997db1933ddaddaa896286 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 16:59:08 -0500 Subject: [PATCH 146/188] Update build-and-deploy.yml --- .github/workflows/build-and-deploy.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 97d3596..971daa2 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -18,19 +18,6 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v3 - - - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: 23 - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 - - - name: Build with Gradle (backend) - run: | - cd backend - ./gradlew bootJar - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 From a66a8f0e4ebda969a4c1bd4805ed5110142d7d37 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 17:01:37 -0500 Subject: [PATCH 147/188] Use bucket name for database --- backend/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main.rs b/backend/src/main.rs index f51f9f8..b307ac3 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -44,7 +44,7 @@ async fn main() -> std::io::Result<()> { let mongo_service = Arc::new( MongoService::new( &mongo_url, - "pastebook" + &bucket_name, ) .await .expect("Failed to initialize MongoService") From 8d8ac712b48887f9f9fddf04886ee3c020a236d5 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 17:10:01 -0500 Subject: [PATCH 148/188] Update build-and-deploy.yml --- .github/workflows/build-and-deploy.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 971daa2..95f415d 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -2,9 +2,9 @@ name: Build and Publish Docker Images on: push: - paths: - - frontend/** - - backend/** + # paths: + # - frontend/** + # - backend/** branches: - master - dev @@ -45,7 +45,13 @@ jobs: exit 1 fi echo "branch_tag=${{ env.tag }}" >> $GITHUB_ENV - + + - name: Debug Branch and Tags + run: | + echo "Branch name: ${{ github.ref_name }}" + echo "Tag: ${{ env.tag }}" + echo "Branch tag: ${{ env.branch_tag }}" + - name: Build and push frontend Docker image to GHCR uses: docker/build-push-action@v3 with: From 5c2973844311656178815b039702f02ad1505bca Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 17:11:15 -0500 Subject: [PATCH 149/188] Update build-and-deploy.yml --- .github/workflows/build-and-deploy.yml | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 95f415d..581a98c 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -44,13 +44,6 @@ jobs: echo "Unknown branch: ${{ github.ref_name }}" exit 1 fi - echo "branch_tag=${{ env.tag }}" >> $GITHUB_ENV - - - name: Debug Branch and Tags - run: | - echo "Branch name: ${{ github.ref_name }}" - echo "Tag: ${{ env.tag }}" - echo "Branch tag: ${{ env.branch_tag }}" - name: Build and push frontend Docker image to GHCR uses: docker/build-push-action@v3 @@ -61,7 +54,7 @@ jobs: COMMIT_HASH=${{ env.hash }} push: true tags: | - ghcr.io/loudbooks/pastebook-frontend:${{ env.branch_tag }} + ghcr.io/loudbooks/pastebook-frontend:${{ env.tag }} ghcr.io/loudbooks/pastebook-frontend:${{ env.hash }} - name: Build and push backend Docker image to GHCR @@ -71,7 +64,7 @@ jobs: file: ./backend/Dockerfile push: true tags: | - ghcr.io/loudbooks/pastebook-backend:${{ env.branch_tag }} + ghcr.io/loudbooks/pastebook-backend:${{ env.tag }} ghcr.io/loudbooks/pastebook-backend:${{ env.hash }} - name: Log in to Docker Hub @@ -89,7 +82,7 @@ jobs: file: ./frontend/Dockerfile push: true tags: | - ${{ secrets.DOCKER_USERNAME }}/pastebook-frontend:${{ env.branch_tag }} + ${{ secrets.DOCKER_USERNAME }}/pastebook-frontend:${{ env.tag }} ${{ secrets.DOCKER_USERNAME }}/pastebook-frontend:${{ env.hash }} - name: Build and push backend Docker image to Docker Hub @@ -99,5 +92,5 @@ jobs: file: ./backend/Dockerfile push: true tags: | - ${{ secrets.DOCKER_USERNAME }}/pastebook-backend:${{ env.branch_tag }} + ${{ secrets.DOCKER_USERNAME }}/pastebook-backend:${{ env.tag }} ${{ secrets.DOCKER_USERNAME }}/pastebook-backend:${{ env.hash }} From e5deff9b14dde6b861d834a01b3b16b0fc7fa927 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 17:13:43 -0500 Subject: [PATCH 150/188] Optimize Dockerfile --- backend/Dockerfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 06750c7..4e0300a 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,11 +1,12 @@ FROM rust:latest as builder COPY ./Cargo.toml ./Cargo.lock ./ +RUN cargo fetch COPY ./src ./src -RUN cargo build +RUN cargo build --release -FROM rust:latest +FROM debian:bullseye-slim -COPY --from=builder target/debug/backend /usr/local/bin/backend +COPY --from=builder target/release/backend /usr/local/bin/backend CMD ["/usr/local/bin/backend"] \ No newline at end of file From d2d6183106dc49ba3e7b4b90cf615588a44bb0e8 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 17:16:08 -0500 Subject: [PATCH 151/188] Target --- backend/Cargo.toml | 6 +++++- backend/Dockerfile | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 2aeaffd..d99665b 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -17,4 +17,8 @@ log = "0.4.22" dotenv = "0.15" futures-util = "0.3.31" aws-credential-types = { version = "1.2.1", features = ["hardcoded-credentials"] } -env_logger = "0.11.5" \ No newline at end of file +env_logger = "0.11.5" + +[[bin]] +name = "backend" +path = "src/main.rs" \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile index 4e0300a..61f057b 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest as builder +FROM rust:latest AS builder COPY ./Cargo.toml ./Cargo.lock ./ RUN cargo fetch From 4792ebd93386b48bfbecaa7fe23b315d0429b2f0 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 17:26:13 -0500 Subject: [PATCH 152/188] Cors fix --- backend/Cargo.lock | 16 ++++++++++++++++ backend/Cargo.toml | 1 + backend/src/main.rs | 15 ++++++--------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index a02456d..13c9fb2 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -19,6 +19,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "actix-cors" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9e772b3bcafe335042b5db010ab7c09013dad6eac4915c91d8d50902769f331" +dependencies = [ + "actix-utils", + "actix-web", + "derive_more", + "futures-util", + "log", + "once_cell", + "smallvec", +] + [[package]] name = "actix-http" version = "3.9.0" @@ -601,6 +616,7 @@ dependencies = [ name = "backend" version = "0.1.0" dependencies = [ + "actix-cors", "actix-web", "anyhow", "aws-credential-types", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index d99665b..f60dc62 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] actix-web = "4" +actix-cors = "0.7.0" mongodb = "3.1.0" aws-sdk-s3 = { version = "1.65.0" } tokio = { version = "1", features = ["full"] } diff --git a/backend/src/main.rs b/backend/src/main.rs index b307ac3..569b1f3 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -15,7 +15,7 @@ use actix_web::{web, App, HttpResponse, HttpServer, Responder}; use dotenv::dotenv; use std::env; use std::sync::Arc; -use aws_sdk_s3::types::builders::CorsRuleBuilder; +use actix_cors::Cors; #[actix_web::main] async fn main() -> std::io::Result<()> { @@ -52,15 +52,12 @@ async fn main() -> std::io::Result<()> { let delete_handler = DeleteHandler::new(Arc::clone(&aws_service), Arc::clone(&mongo_service)); delete_handler.start_delete_loop(); - - let cors = CorsRuleBuilder::default() - .allowed_origins(vec!["*"]) - .allowed_methods(vec!["GET", "POST"]) - .allowed_headers(vec!["*"]) - .build(); - + HttpServer::new(move || { - App::new().wrap(cors) + let cors = Cors::permissive(); + + App::new() + .wrap(cors) .app_data(web::Data::new(Arc::clone(&aws_service))) .app_data(web::Data::new(Arc::clone(&mongo_service))) .route("/get/{id}/content", web::get().to(get_content_handler)) From c1019daf71610c51b90d9db44804a82da48f31bf Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 17:37:30 -0500 Subject: [PATCH 153/188] Ubuntu --- backend/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 61f057b..bbfd04e 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -5,7 +5,7 @@ RUN cargo fetch COPY ./src ./src RUN cargo build --release -FROM debian:bullseye-slim +FROM ubuntu/latest COPY --from=builder target/release/backend /usr/local/bin/backend From 8682144c5f3e47d1d678b7602b46e384a344fe91 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 17:40:42 -0500 Subject: [PATCH 154/188] Ubuntu Noble --- backend/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index bbfd04e..ce88737 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -5,7 +5,7 @@ RUN cargo fetch COPY ./src ./src RUN cargo build --release -FROM ubuntu/latest +FROM ubuntu:noble COPY --from=builder target/release/backend /usr/local/bin/backend From 84c67a6149040b6845e68711e44d74db176fedee Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 17:49:31 -0500 Subject: [PATCH 155/188] Alpine --- backend/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index ce88737..a4de00a 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -3,9 +3,9 @@ FROM rust:latest AS builder COPY ./Cargo.toml ./Cargo.lock ./ RUN cargo fetch COPY ./src ./src -RUN cargo build --release +RUN cargo build --release --target x86_64-unknown-linux-musl -FROM ubuntu:noble +FROM alpine:latest COPY --from=builder target/release/backend /usr/local/bin/backend From ac33784e12303266b6b089c4b70c33bc5b3e5d5e Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 18:01:46 -0500 Subject: [PATCH 156/188] 24.04 --- backend/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index a4de00a..9c728a4 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -3,9 +3,9 @@ FROM rust:latest AS builder COPY ./Cargo.toml ./Cargo.lock ./ RUN cargo fetch COPY ./src ./src -RUN cargo build --release --target x86_64-unknown-linux-musl +RUN cargo build --release -FROM alpine:latest +FROM ubuntu:24.04 COPY --from=builder target/release/backend /usr/local/bin/backend From d9d25075156dd4826facdf9f32435c83249e88e3 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 18:11:04 -0500 Subject: [PATCH 157/188] Bullseye --- backend/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 9c728a4..2866901 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -5,8 +5,9 @@ RUN cargo fetch COPY ./src ./src RUN cargo build --release -FROM ubuntu:24.04 +FROM debian:bullseye +RUN apt-get update && apt-get install -y libc6 COPY --from=builder target/release/backend /usr/local/bin/backend CMD ["/usr/local/bin/backend"] \ No newline at end of file From a4e24924991fb20adb1c2c99416c5a3fe180eaf2 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 18:18:12 -0500 Subject: [PATCH 158/188] Bookwork --- backend/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 2866901..e864549 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -5,7 +5,7 @@ RUN cargo fetch COPY ./src ./src RUN cargo build --release -FROM debian:bullseye +FROM debian:bookworm RUN apt-get update && apt-get install -y libc6 COPY --from=builder target/release/backend /usr/local/bin/backend From 1b092460d31e9a8afc3461cbb0e45702168d7753 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 18:30:33 -0500 Subject: [PATCH 159/188] Bookworm --- backend/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index e864549..bd5d3bc 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,11 +1,11 @@ -FROM rust:latest AS builder +FROM rust:slim-bookworm AS builder COPY ./Cargo.toml ./Cargo.lock ./ RUN cargo fetch COPY ./src ./src RUN cargo build --release -FROM debian:bookworm +FROM debian:bookworm-slim RUN apt-get update && apt-get install -y libc6 COPY --from=builder target/release/backend /usr/local/bin/backend From 9dede694809f95ca12bea844638ab3b121385887 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 18:34:51 -0500 Subject: [PATCH 160/188] Target musl --- backend/Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index bd5d3bc..4cfdbd0 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -3,7 +3,9 @@ FROM rust:slim-bookworm AS builder COPY ./Cargo.toml ./Cargo.lock ./ RUN cargo fetch COPY ./src ./src -RUN cargo build --release + +RUN rustup target add x86_64-unknown-linux-musl +RUN cargo build --release --target x86_64-unknown-linux-musl FROM debian:bookworm-slim From 53958810e90fb794ca33800184cacc301d25f4fd Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 18:37:52 -0500 Subject: [PATCH 161/188] MUSL Tools --- backend/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/Dockerfile b/backend/Dockerfile index 4cfdbd0..37366b9 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -5,6 +5,7 @@ RUN cargo fetch COPY ./src ./src RUN rustup target add x86_64-unknown-linux-musl +RUN apt-get update && apt-get install -y musl-tools RUN cargo build --release --target x86_64-unknown-linux-musl FROM debian:bookworm-slim From acab86f39c37953315e920e0d9bcc1fe1c811e55 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 18:43:12 -0500 Subject: [PATCH 162/188] Fix path --- backend/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 37366b9..d18f8a9 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -11,6 +11,6 @@ RUN cargo build --release --target x86_64-unknown-linux-musl FROM debian:bookworm-slim RUN apt-get update && apt-get install -y libc6 -COPY --from=builder target/release/backend /usr/local/bin/backend +COPY --from=builder target/x86_64-unknown-linux-musl/release/backend /usr/local/bin/backend CMD ["/usr/local/bin/backend"] \ No newline at end of file From 4419650eee3be94d628d5e922140f436e6951fb8 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 18:52:29 -0500 Subject: [PATCH 163/188] Non slim --- backend/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index d18f8a9..7d0b99a 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:slim-bookworm AS builder +FROM rust:latest AS builder COPY ./Cargo.toml ./Cargo.lock ./ RUN cargo fetch @@ -8,7 +8,7 @@ RUN rustup target add x86_64-unknown-linux-musl RUN apt-get update && apt-get install -y musl-tools RUN cargo build --release --target x86_64-unknown-linux-musl -FROM debian:bookworm-slim +FROM debian:bookworm RUN apt-get update && apt-get install -y libc6 COPY --from=builder target/x86_64-unknown-linux-musl/release/backend /usr/local/bin/backend From fee9cd37db16a5a6a44c5927c3b7ed4802132bea Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 19:03:42 -0500 Subject: [PATCH 164/188] dockerignore --- backend/.dockerignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 backend/.dockerignore diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..c41cc9e --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1 @@ +/target \ No newline at end of file From 0d86777e83c4fd64ef71ac98cea721d2ce182549 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 19:20:43 -0500 Subject: [PATCH 165/188] Revert dockerignore --- backend/.dockerignore | 1 - backend/Dockerfile | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 backend/.dockerignore diff --git a/backend/.dockerignore b/backend/.dockerignore deleted file mode 100644 index c41cc9e..0000000 --- a/backend/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -/target \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile index 7d0b99a..a407838 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest AS builder +FROM rust:bookworm AS builder COPY ./Cargo.toml ./Cargo.lock ./ RUN cargo fetch From b143bef40cd70d30d762b35c3dd9e407d686cc42 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 19:26:53 -0500 Subject: [PATCH 166/188] alpine all --- backend/Dockerfile | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index a407838..aa5067b 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,16 +1,12 @@ -FROM rust:bookworm AS builder +FROM rust:1.83.0-alpine AS builder -COPY ./Cargo.toml ./Cargo.lock ./ -RUN cargo fetch -COPY ./src ./src +COPY . . -RUN rustup target add x86_64-unknown-linux-musl -RUN apt-get update && apt-get install -y musl-tools -RUN cargo build --release --target x86_64-unknown-linux-musl +RUN apk add --no-cache clang lld musl-dev git +RUN cargo build --release --locked -FROM debian:bookworm +FROM alpine:3.18 AS final -RUN apt-get update && apt-get install -y libc6 -COPY --from=builder target/x86_64-unknown-linux-musl/release/backend /usr/local/bin/backend +COPY --from=builder target/release/backend /usr/local/bin/backend CMD ["/usr/local/bin/backend"] \ No newline at end of file From 990b453c7322a55c3a562973818401a34c91cce7 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 20:02:41 -0500 Subject: [PATCH 167/188] Cleanup --- backend/src/delete_service.rs | 10 ++++++---- backend/src/main.rs | 11 +++-------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/backend/src/delete_service.rs b/backend/src/delete_service.rs index c314b85..848038f 100644 --- a/backend/src/delete_service.rs +++ b/backend/src/delete_service.rs @@ -64,10 +64,12 @@ impl DeleteHandler { if let Err(err) = mongo_service.delete_paste(paste_id).await { error!("Failed to delete paste from database: {:?}", err); } - if let id = &paste.id { - if let Err(err) = mongo_service.delete_paste(id).await { - error!("Failed to delete paste file: {}", err); - } + let id = &paste.id; + + if let Err(err) = mongo_service.delete_paste(id).await { + error!("Failed to delete paste file: {}", err); + } else { + warn!("Deleted paste file: {}", id); } } diff --git a/backend/src/main.rs b/backend/src/main.rs index 569b1f3..9e11a9c 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -11,11 +11,11 @@ use crate::controllers::get_controller::{get_content_handler, get_metadata_handl use crate::controllers::upload_controller::upload_handler; use crate::delete_service::DeleteHandler; use crate::mongodb_service::MongoService; -use actix_web::{web, App, HttpResponse, HttpServer, Responder}; +use actix_cors::Cors; +use actix_web::{web, App, HttpServer}; use dotenv::dotenv; use std::env; use std::sync::Arc; -use actix_cors::Cors; #[actix_web::main] async fn main() -> std::io::Result<()> { @@ -52,7 +52,7 @@ async fn main() -> std::io::Result<()> { let delete_handler = DeleteHandler::new(Arc::clone(&aws_service), Arc::clone(&mongo_service)); delete_handler.start_delete_loop(); - + HttpServer::new(move || { let cors = Cors::permissive(); @@ -67,9 +67,4 @@ async fn main() -> std::io::Result<()> { .bind(("0.0.0.0", 8080))? .run() .await -} - -async fn health_check() -> impl Responder { - println!("Health check"); - HttpResponse::Ok().body("OK") } \ No newline at end of file From a0c2b85910b80d920134ec6cc4032ca1c08889e6 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 20:10:04 -0500 Subject: [PATCH 168/188] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dd6af11..e9e5504 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # PasteBook -An easy on the eyes, portable, lightning fast pastebin written in Svelte and Kotlin. +An easy on the eyes, portable, lightning fast pastebin written in Svelte and Rust. ### Prerequisites Docker. Both the frontend and backend are to be installed with Docker. You can learn more [here](https://www.docker.com). @@ -73,9 +73,11 @@ systemctl restart nginx Run the following commands in succession. ```bash docker compose stop +docker compose pull docker compose up -d ``` # Final Notes Wow. There was a lot that can go wrong there. I'm not an expert. If you need help, you can email me at contact@loudbook.dev or find me elsewhere. + 💜 From af53acdbb9e80a58cf527e7e33483fe78d530d38 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 20:10:30 -0500 Subject: [PATCH 169/188] Update build-and-deploy.yml --- .github/workflows/build-and-deploy.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 581a98c..dcac62e 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -2,9 +2,9 @@ name: Build and Publish Docker Images on: push: - # paths: - # - frontend/** - # - backend/** + paths: + - frontend/** + - backend/** branches: - master - dev From 0029c9eab6ee3aa89a053a75b6d27f7fbc48f89c Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 20:24:36 -0500 Subject: [PATCH 170/188] Rename to expiresAt --- backend/src/controllers/upload_controller.rs | 2 +- backend/src/delete_service.rs | 2 +- backend/src/models/paste.rs | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/backend/src/controllers/upload_controller.rs b/backend/src/controllers/upload_controller.rs index 61ed386..57002a1 100644 --- a/backend/src/controllers/upload_controller.rs +++ b/backend/src/controllers/upload_controller.rs @@ -69,7 +69,7 @@ pub async fn upload_handler( report_book, wrap, creator_ip: ip.clone(), - expires, + expires_at: expires, }; if let Err(e) = aws_service.put_file(&file_id, (&body).as_ref()).await { diff --git a/backend/src/delete_service.rs b/backend/src/delete_service.rs index 848038f..55ffef2 100644 --- a/backend/src/delete_service.rs +++ b/backend/src/delete_service.rs @@ -51,7 +51,7 @@ impl DeleteHandler { while let Some(paste) = pastes_cursor.next().await { let paste = paste.expect("Failed to get paste"); - if paste.expires > 0 && paste.expires < now as u64 { + if paste.expires_at > 0 && paste.expires_at < now as u64 { deletable_pastes.push(paste.clone()); } diff --git a/backend/src/models/paste.rs b/backend/src/models/paste.rs index 2786c4d..930c642 100644 --- a/backend/src/models/paste.rs +++ b/backend/src/models/paste.rs @@ -9,7 +9,8 @@ pub struct Paste { pub report_book: bool, pub wrap: bool, pub creator_ip: String, - pub expires: u64, + #[serde(rename = "expiresAt")] + pub expires_at: u64, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -20,7 +21,8 @@ pub struct PasteDTO { pub created: u64, pub report_book: bool, pub wrap: bool, - pub expires: u64, + #[serde(rename = "expiresAt")] + pub expires_at: u64, } impl Paste { @@ -32,7 +34,7 @@ impl Paste { created: self.created, report_book: self.report_book, wrap: self.wrap, - expires: self.expires, + expires_at: self.expires_at, } } } From 7e8c0278cb676254c3001e4801fbd5c6885bf442 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 20:33:38 -0500 Subject: [PATCH 171/188] Change to matrix build --- .github/workflows/build-and-deploy.yml | 129 +++++++++++-------------- 1 file changed, 55 insertions(+), 74 deletions(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index dcac62e..094dbf0 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -8,89 +8,70 @@ on: branches: - master - dev - + jobs: build: runs-on: ubuntu-latest permissions: packages: write - + strategy: + matrix: + component: [frontend, backend] steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 - - name: Log in to GHCR - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Get Commit Hash - id: get_commit_hash - run: echo "hash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + - name: Log in to GHCR + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: Set Docker Tags - id: set_tags - run: | - if [ "${{ github.ref_name }}" == "master" ]; then - echo "tag=latest" >> $GITHUB_ENV - elif [ "${{ github.ref_name }}" == "dev" ]; then - echo "tag=dev" >> $GITHUB_ENV - else - echo "Unknown branch: ${{ github.ref_name }}" - exit 1 - fi - - - name: Build and push frontend Docker image to GHCR - uses: docker/build-push-action@v3 - with: - context: ./frontend - file: ./frontend/Dockerfile - build-args: | - COMMIT_HASH=${{ env.hash }} - push: true - tags: | - ghcr.io/loudbooks/pastebook-frontend:${{ env.tag }} - ghcr.io/loudbooks/pastebook-frontend:${{ env.hash }} + - name: Get Commit Hash + id: get_commit_hash + run: echo "hash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV - - name: Build and push backend Docker image to GHCR - uses: docker/build-push-action@v3 - with: - context: ./backend - file: ./backend/Dockerfile - push: true - tags: | - ghcr.io/loudbooks/pastebook-backend:${{ env.tag }} - ghcr.io/loudbooks/pastebook-backend:${{ env.hash }} + - name: Set Docker Tags + id: set_tags + run: | + if [ "${{ github.ref_name }}" == "master" ]; then + echo "tag=latest" >> $GITHUB_ENV + elif [ "${{ github.ref_name }}" == "dev" ]; then + echo "tag=dev" >> $GITHUB_ENV + else + echo "Unknown branch: ${{ github.ref_name }}" + exit 1 - - name: Log in to Docker Hub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_TOKEN }} + - name: Build and push Docker image to GHCR + uses: docker/build-push-action@v3 + with: + context: ./${{ matrix.component }} + file: ./${{ matrix.component }}/Dockerfile + build-args: | + COMMIT_HASH=${{ env.hash }} + push: true + tags: | + ghcr.io/loudbooks/pastebook-${{ matrix.component }}:${{ env.tag }} + ghcr.io/loudbooks/pastebook-${{ matrix.component }}:${{ env.hash }} - - name: Build and push frontend Docker image to Docker Hub - uses: docker/build-push-action@v3 - with: - context: ./frontend - build-args: | - COMMIT_HASH=${{ env.hash }} - file: ./frontend/Dockerfile - push: true - tags: | - ${{ secrets.DOCKER_USERNAME }}/pastebook-frontend:${{ env.tag }} - ${{ secrets.DOCKER_USERNAME }}/pastebook-frontend:${{ env.hash }} + - name: Log in to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} - - name: Build and push backend Docker image to Docker Hub - uses: docker/build-push-action@v3 - with: - context: ./backend - file: ./backend/Dockerfile - push: true - tags: | - ${{ secrets.DOCKER_USERNAME }}/pastebook-backend:${{ env.tag }} - ${{ secrets.DOCKER_USERNAME }}/pastebook-backend:${{ env.hash }} + - name: Build and push Docker image to Docker Hub + uses: docker/build-push-action@v3 + with: + context: ./${{ matrix.component }} + file: ./${{ matrix.component }}/Dockerfile + build-args: | + COMMIT_HASH=${{ env.hash }} + push: true + tags: | + ${{ secrets.DOCKER_USERNAME }}/pastebook-${{ matrix.component }}:${{ env.tag }} + ${{ secrets.DOCKER_USERNAME }}/pastebook-${{ matrix.component }}:${{ env.hash }} From 1d6956fb19769e7e4cf2439284235d6ebd60f7fe Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 20:38:15 -0500 Subject: [PATCH 172/188] Don't need to rename --- backend/src/models/paste.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/models/paste.rs b/backend/src/models/paste.rs index 930c642..3f3d316 100644 --- a/backend/src/models/paste.rs +++ b/backend/src/models/paste.rs @@ -9,7 +9,6 @@ pub struct Paste { pub report_book: bool, pub wrap: bool, pub creator_ip: String, - #[serde(rename = "expiresAt")] pub expires_at: u64, } @@ -21,7 +20,6 @@ pub struct PasteDTO { pub created: u64, pub report_book: bool, pub wrap: bool, - #[serde(rename = "expiresAt")] pub expires_at: u64, } From 1dd34cb868e2d5d8a3e61c2acf9bce0259dd7a9e Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 20:47:46 -0500 Subject: [PATCH 173/188] Update build-and-deploy.yml --- .github/workflows/build-and-deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 094dbf0..995f346 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -45,6 +45,7 @@ jobs: else echo "Unknown branch: ${{ github.ref_name }}" exit 1 + fi - name: Build and push Docker image to GHCR uses: docker/build-push-action@v3 From f3a4712331d3b40645c8f5c432bd062b44de303c Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 20:48:22 -0500 Subject: [PATCH 174/188] Update build-and-deploy.yml --- .github/workflows/build-and-deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 995f346..928945e 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -1,6 +1,7 @@ name: Build and Publish Docker Images on: + workflow_dispatch: push: paths: - frontend/** From b08a41fe9466ab4ce278eeb075a8815b7ca4be50 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 20:49:15 -0500 Subject: [PATCH 175/188] Update build-and-deploy.yml --- .github/workflows/build-and-deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 58d0850..53321d3 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -1,6 +1,7 @@ name: Build and Publish Docker Images on: + workflow_dispatch: push: paths: - frontend/** From e0e93e263350c427bdd2ba83229be47a45cfd553 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 20:50:13 -0500 Subject: [PATCH 176/188] No need for dotenv --- backend/Cargo.lock | 7 ------- backend/Cargo.toml | 1 - backend/src/main.rs | 2 -- 3 files changed, 10 deletions(-) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 13c9fb2..940d7e5 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -622,7 +622,6 @@ dependencies = [ "aws-credential-types", "aws-sdk-s3", "chrono", - "dotenv", "env_logger", "flate2", "futures-util", @@ -1043,12 +1042,6 @@ dependencies = [ "syn 2.0.90", ] -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - [[package]] name = "ecdsa" version = "0.14.8" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index f60dc62..ef6e734 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -15,7 +15,6 @@ flate2 = "1.0.35" chrono = "0.4.39" rand = "0.8.5" log = "0.4.22" -dotenv = "0.15" futures-util = "0.3.31" aws-credential-types = { version = "1.2.1", features = ["hardcoded-credentials"] } env_logger = "0.11.5" diff --git a/backend/src/main.rs b/backend/src/main.rs index 9e11a9c..d5cf34a 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -13,14 +13,12 @@ use crate::delete_service::DeleteHandler; use crate::mongodb_service::MongoService; use actix_cors::Cors; use actix_web::{web, App, HttpServer}; -use dotenv::dotenv; use std::env; use std::sync::Arc; #[actix_web::main] async fn main() -> std::io::Result<()> { env_logger::init(); - dotenv().ok(); let database_url = env::var("S3_ENDPOINT").expect("S3_ENDPOINT must be set"); let aws_access_key = env::var("S3_ACCESS_KEY_ID").expect("S3_ACCESS_KEY_ID must be set"); From efd6e0b8c13d644acac059222634e7b004f8dd91 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Tue, 10 Dec 2024 22:02:13 -0500 Subject: [PATCH 177/188] Fewer dependencies --- backend/Cargo.lock | 18 ++++++++++++++++++ backend/Cargo.toml | 10 +++++----- backend/src/delete_service.rs | 4 ++-- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 940d7e5..bce6f24 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -1153,6 +1153,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", + "libz-sys", "miniz_oxide", ] @@ -1786,6 +1787,17 @@ version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +[[package]] +name = "libz-sys" +version = "1.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -2907,6 +2919,12 @@ dependencies = [ "serde", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index ef6e734..2ab4c49 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -8,16 +8,16 @@ actix-web = "4" actix-cors = "0.7.0" mongodb = "3.1.0" aws-sdk-s3 = { version = "1.65.0" } -tokio = { version = "1", features = ["full"] } -anyhow = "1.0.94" +tokio = { version = "1", features = ["rt"] } +anyhow = { version = "1.0.40", default-features = false } serde = { version = "1.0.215", features = ["derive"] } -flate2 = "1.0.35" -chrono = "0.4.39" +flate2 = { version = "1.0.19", features = ["zlib"] } +chrono = { version = "0.4.19", features = ["serde"] } rand = "0.8.5" -log = "0.4.22" futures-util = "0.3.31" aws-credential-types = { version = "1.2.1", features = ["hardcoded-credentials"] } env_logger = "0.11.5" +log = "0.4.22" [[bin]] name = "backend" diff --git a/backend/src/delete_service.rs b/backend/src/delete_service.rs index 55ffef2..8f59397 100644 --- a/backend/src/delete_service.rs +++ b/backend/src/delete_service.rs @@ -2,9 +2,9 @@ use std::sync::Arc; use std::time::Duration; use chrono::Utc; use futures_util::StreamExt; -use log::{error, warn}; use tokio::spawn; use tokio::time::interval; +use log::{error, warn}; use crate::aws_service::AWSService; use crate::mongodb_service::MongoService; @@ -65,7 +65,7 @@ impl DeleteHandler { error!("Failed to delete paste from database: {:?}", err); } let id = &paste.id; - + if let Err(err) = mongo_service.delete_paste(id).await { error!("Failed to delete paste file: {}", err); } else { From ffeefca1a6930110905786329fd74732c07a6d27 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Wed, 11 Dec 2024 09:41:35 -0500 Subject: [PATCH 178/188] Test MacOS Build --- .github/workflows/build-and-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 928945e..9e72e19 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -12,7 +12,7 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: macos-latest permissions: packages: write strategy: From b43ca5b98680b2a1284a70033e9fa4ce59887b5e Mon Sep 17 00:00:00 2001 From: Loudbook Date: Wed, 11 Dec 2024 09:43:05 -0500 Subject: [PATCH 179/188] Update build-and-deploy.yml --- .github/workflows/build-and-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 9e72e19..928945e 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -12,7 +12,7 @@ on: jobs: build: - runs-on: macos-latest + runs-on: ubuntu-latest permissions: packages: write strategy: From ee764ae49a887b8a69ea58b463827fd188bcc47e Mon Sep 17 00:00:00 2001 From: Loudbook Date: Wed, 11 Dec 2024 14:15:56 -0500 Subject: [PATCH 180/188] MongoDB Migration --- backend/src/controllers/get_controller.rs | 4 +- backend/src/controllers/upload_controller.rs | 4 +- backend/src/{ => database}/aws_service.rs | 0 backend/src/database/migration_service.rs | 136 ++++++++++++++++++ backend/src/database/mod.rs | 5 + backend/src/{ => database}/mongodb_service.rs | 9 +- backend/src/{ => database}/mongoresult.rs | 0 backend/src/delete_service.rs | 4 +- backend/src/main.rs | 8 +- 9 files changed, 157 insertions(+), 13 deletions(-) rename backend/src/{ => database}/aws_service.rs (100%) create mode 100644 backend/src/database/migration_service.rs create mode 100644 backend/src/database/mod.rs rename backend/src/{ => database}/mongodb_service.rs (86%) rename backend/src/{ => database}/mongoresult.rs (100%) diff --git a/backend/src/controllers/get_controller.rs b/backend/src/controllers/get_controller.rs index bcc6e9e..3264802 100644 --- a/backend/src/controllers/get_controller.rs +++ b/backend/src/controllers/get_controller.rs @@ -1,10 +1,10 @@ -use crate::aws_service::AWSService; +use crate::database::aws_service::AWSService; use actix_web::{ web, HttpRequest, HttpResponse, Responder, }; use serde::Deserialize; use std::sync::Arc; -use crate::mongodb_service::MongoService; +use crate::database::mongodb_service::MongoService; #[derive(Deserialize)] pub struct ContentQuery { diff --git a/backend/src/controllers/upload_controller.rs b/backend/src/controllers/upload_controller.rs index 57002a1..7f178c0 100644 --- a/backend/src/controllers/upload_controller.rs +++ b/backend/src/controllers/upload_controller.rs @@ -1,6 +1,6 @@ -use crate::aws_service::AWSService; +use crate::database::aws_service::AWSService; use crate::models::paste::Paste; -use crate::mongodb_service::MongoService; +use crate::database::mongodb_service::MongoService; use crate::utils::iputils::IPUtils; use actix_web::{web, HttpRequest, HttpResponse, Responder}; use rand::{distributions::Alphanumeric, thread_rng, Rng}; diff --git a/backend/src/aws_service.rs b/backend/src/database/aws_service.rs similarity index 100% rename from backend/src/aws_service.rs rename to backend/src/database/aws_service.rs diff --git a/backend/src/database/migration_service.rs b/backend/src/database/migration_service.rs new file mode 100644 index 0000000..412a335 --- /dev/null +++ b/backend/src/database/migration_service.rs @@ -0,0 +1,136 @@ +use crate::models::paste::Paste; +use crate::models::user::User; +use futures_util::StreamExt; +use mongodb::bson::{doc, Document}; +use mongodb::{Collection, Database}; + +pub struct MigrationService { + database: Database, + admin_database: Database, + users_collection: Collection, + pastes_collection: Collection, +} + +impl MigrationService { + pub fn new(database: &Database, admin_database: &Database, users_collection: &Collection, pastes_collection: &Collection) -> Self { + Self { + database: database.clone(), + admin_database: admin_database.clone(), + users_collection: users_collection.clone(), + pastes_collection: pastes_collection.clone(), + } + } + + pub async fn run_migrations(&self) { + self.user_migration_12_11_24().await.map_err(|e| println!("Error migrating users: {}", e)).ok(); + self.paste_migration_12_11_24().await.map_err(|e| println!("Error migrating pastes: {}", e)).ok(); + } + + pub async fn user_migration_12_11_24(&self) -> Result<(), mongodb::error::Error> { + if !self.database.list_collection_names().await?.contains(&"user".to_string()) { + println!("No users to migrate."); + return Ok(()); + } + + println!("Migrating users..."); + let old_user_collection = self.database.collection::("user"); + + let mut amount = 0; + let target_amount = old_user_collection.count_documents(doc! {}).await?; + let mut cursor = old_user_collection.find(doc! {}).await?; + + while let Some(old_user) = cursor.next().await { + let old_user = old_user?; + let user_ip = old_user.get_str("_id").unwrap_or_default(); + let user_id = old_user.get_str("id").unwrap_or_default(); + let user_requests = old_user.get_i32("requests").unwrap_or_default(); + let user_banned = old_user.get_bool("banned").unwrap_or_default(); + let last_visit = old_user.get_i64("lastVisit").unwrap_or_default(); + + if user_ip.is_empty() || user_id.is_empty() { + println!("Skipping user with empty IP or ID."); + continue; + } + + let user = User { + ip: user_ip.to_string(), + id: user_id.to_string(), + requests: user_requests as u64, + created_at: last_visit, + banned: user_banned, + }; + + self.users_collection.insert_one(user).await?; + + amount += 1; + } + + println!("Migrated {} out of {} users", amount, target_amount); + + let qualified_old_database_name = self.database.name().to_owned() + ".user"; + let qualified_new_database_name = self.database.name().to_owned() + ".user_migrated_12_11_24"; + + self.admin_database.run_command(doc! { + "renameCollection": qualified_old_database_name, + "to": qualified_new_database_name, + "dropTarget": true + }).await?; + + Ok(()) + } + + pub async fn paste_migration_12_11_24(&self) -> Result<(), mongodb::error::Error> { + if !self.database.list_collection_names().await?.contains(&"pastePrivateDTO".to_string()) { + println!("No pastes to migrate."); + } + + println!("Migrating pastes..."); + let old_paste_collection = self.database.collection::("pastePrivateDTO"); + + let mut amount = 0; + let target_amount = old_paste_collection.count_documents(doc! {}).await?; + let mut cursor = old_paste_collection.find(doc! {}).await?; + + while let Some(old_paste) = cursor.next().await { + let old_paste = old_paste?; + let paste_id = old_paste.get_str("_id").unwrap_or_default(); + let paste_expires_at = old_paste.get_i64("expires").unwrap_or_default(); + let paste_created_at = old_paste.get_i64("created").unwrap_or_default(); + let paste_creator_ip = old_paste.get_str("creatorIP").unwrap_or_default(); + let paste_report_book = old_paste.get_bool("reportBook").unwrap_or_default(); + let paste_wrap = old_paste.get_bool("wrap").unwrap_or_default(); + + if paste_id.is_empty() { + println!("Skipping paste with empty ID."); + continue; + } + + let paste = Paste { + id: paste_id.to_string(), + title: "".to_string(), + created: paste_created_at as u64, + report_book: paste_report_book, + wrap: paste_wrap, + creator_ip: paste_creator_ip.to_string(), + expires_at: paste_expires_at as u64, + }; + + self.pastes_collection.insert_one(paste).await?; + + amount += 1; + } + + println!("Migrated {} out of {} pastes", amount, target_amount); + + let qualified_old_database_name = self.database.name().to_owned() + ".pastePrivateDTO"; + let qualified_new_database_name = self.database.name().to_owned() + ".pastePrivateDTO_migrated_12_11_24"; + + self.admin_database.run_command(doc! { + "renameCollection": qualified_old_database_name, + "to": qualified_new_database_name, + "dropTarget": true + }).await?; + + Ok(()) + } +} \ No newline at end of file diff --git a/backend/src/database/mod.rs b/backend/src/database/mod.rs new file mode 100644 index 0000000..ffa89f5 --- /dev/null +++ b/backend/src/database/mod.rs @@ -0,0 +1,5 @@ +pub mod aws_service; +pub mod mongodb_service; +pub mod mongoresult; + +mod migration_service; \ No newline at end of file diff --git a/backend/src/mongodb_service.rs b/backend/src/database/mongodb_service.rs similarity index 86% rename from backend/src/mongodb_service.rs rename to backend/src/database/mongodb_service.rs index db2e1cc..a56690d 100644 --- a/backend/src/mongodb_service.rs +++ b/backend/src/database/mongodb_service.rs @@ -1,9 +1,10 @@ use mongodb::bson::{doc, uuid}; use mongodb::{Client, Collection, Cursor}; use mongodb::options::ClientOptions; +use crate::database::migration_service::MigrationService; use crate::models::paste::Paste; use crate::models::user::User; -use crate::mongoresult::MongoResult; +use crate::database::mongoresult::MongoResult; pub struct MongoService { user_collection: Collection, @@ -17,10 +18,14 @@ impl MongoService { let client = Client::with_options(client_options)?; let database = client.database(db_name); + let admin_database = client.database("admin"); let user_collection = database.collection::("users"); let paste_collection = database.collection::("pastes"); println!("Connected to MongoDB"); + + let migration_service = MigrationService::new(&database, &admin_database, &user_collection, &paste_collection); + migration_service.run_migrations().await; Ok(Self { user_collection, @@ -33,7 +38,7 @@ impl MongoService { let update = doc! { "$inc": { "requests": 1 }, "$setOnInsert": { - "id": uuid::Uuid::new().to_string(), + "_id": uuid::Uuid::new().to_string(), "created_at": chrono::Utc::now().timestamp_millis(), "banned": false } diff --git a/backend/src/mongoresult.rs b/backend/src/database/mongoresult.rs similarity index 100% rename from backend/src/mongoresult.rs rename to backend/src/database/mongoresult.rs diff --git a/backend/src/delete_service.rs b/backend/src/delete_service.rs index 8f59397..aa02abc 100644 --- a/backend/src/delete_service.rs +++ b/backend/src/delete_service.rs @@ -5,8 +5,8 @@ use futures_util::StreamExt; use tokio::spawn; use tokio::time::interval; use log::{error, warn}; -use crate::aws_service::AWSService; -use crate::mongodb_service::MongoService; +use crate::database::aws_service::AWSService; +use crate::database::mongodb_service::MongoService; pub struct DeleteHandler { aws_service: Arc, diff --git a/backend/src/main.rs b/backend/src/main.rs index d5cf34a..5ebf303 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -1,16 +1,14 @@ -mod aws_service; -mod mongodb_service; mod models; mod controllers; -mod mongoresult; mod utils; mod delete_service; +mod database; -use crate::aws_service::AWSService; +use database::aws_service::AWSService; use crate::controllers::get_controller::{get_content_handler, get_metadata_handler}; use crate::controllers::upload_controller::upload_handler; use crate::delete_service::DeleteHandler; -use crate::mongodb_service::MongoService; +use database::mongodb_service::MongoService; use actix_cors::Cors; use actix_web::{web, App, HttpServer}; use std::env; From 36f2f275b07b7fee036b25590215aea15128b2d2 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Wed, 11 Dec 2024 14:23:59 -0500 Subject: [PATCH 181/188] Update expires tag --- .gitignore | 3 ++- frontend/src/lib/paste.ts | 2 +- frontend/src/routes/[pastes=paste]/[slug]/+page.svelte | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index b89a4cd..c3f7faf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .* !.gitignore docker-compose.yml -.idea \ No newline at end of file +.idea +/backend/target diff --git a/frontend/src/lib/paste.ts b/frontend/src/lib/paste.ts index 98a486c..105ce2b 100755 --- a/frontend/src/lib/paste.ts +++ b/frontend/src/lib/paste.ts @@ -7,5 +7,5 @@ export type Paste = { user: { id: string; }; - expiresAt: string; + expires_at: string; }; diff --git a/frontend/src/routes/[pastes=paste]/[slug]/+page.svelte b/frontend/src/routes/[pastes=paste]/[slug]/+page.svelte index c672143..6186d8f 100755 --- a/frontend/src/routes/[pastes=paste]/[slug]/+page.svelte +++ b/frontend/src/routes/[pastes=paste]/[slug]/+page.svelte @@ -28,7 +28,7 @@ reportBook = data.reportBook; wrap = data.wrap; userId = data.user.id; - expires = new Date(data.expiresAt) + expires = new Date(data.expires_at); const reloadTime = () => { timeSinceStr = formatTimeSince(created as unknown as number); From 451ce149219fa081e6e8f1f2e7a34bfe85f38973 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Wed, 11 Dec 2024 14:27:06 -0500 Subject: [PATCH 182/188] Missing return statement --- backend/src/database/aws_service.rs | 2 +- backend/src/database/migration_service.rs | 1 + backend/src/database/mongodb_service.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/src/database/aws_service.rs b/backend/src/database/aws_service.rs index 127c9ba..7a5073f 100644 --- a/backend/src/database/aws_service.rs +++ b/backend/src/database/aws_service.rs @@ -25,7 +25,7 @@ impl AWSService { let client = Client::from_conf(config); - println!("Connected to AWS S3"); + println!("Connected to AWS S3."); Ok(Self { client, diff --git a/backend/src/database/migration_service.rs b/backend/src/database/migration_service.rs index 412a335..65d404b 100644 --- a/backend/src/database/migration_service.rs +++ b/backend/src/database/migration_service.rs @@ -82,6 +82,7 @@ impl MigrationService { pub async fn paste_migration_12_11_24(&self) -> Result<(), mongodb::error::Error> { if !self.database.list_collection_names().await?.contains(&"pastePrivateDTO".to_string()) { println!("No pastes to migrate."); + return Ok(()); } println!("Migrating pastes..."); diff --git a/backend/src/database/mongodb_service.rs b/backend/src/database/mongodb_service.rs index a56690d..771ec2c 100644 --- a/backend/src/database/mongodb_service.rs +++ b/backend/src/database/mongodb_service.rs @@ -22,7 +22,7 @@ impl MongoService { let user_collection = database.collection::("users"); let paste_collection = database.collection::("pastes"); - println!("Connected to MongoDB"); + println!("Connected to MongoDB."); let migration_service = MigrationService::new(&database, &admin_database, &user_collection, &paste_collection); migration_service.run_migrations().await; From a3aeae0586db51a999b1b5266482583801d18eab Mon Sep 17 00:00:00 2001 From: Loudbook Date: Wed, 11 Dec 2024 21:21:43 -0500 Subject: [PATCH 183/188] Max payload configurable --- backend/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/src/main.rs b/backend/src/main.rs index 5ebf303..401a5ee 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -23,6 +23,7 @@ async fn main() -> std::io::Result<()> { let aws_secret_key = env::var("S3_SECRET_ACCESS_KEY").expect("S3_SECRET_ACCESS_KEY must be set"); let bucket_name = env::var("S3_BUCKET").expect("S3_BUCKET must be set"); let mongo_url = env::var("SPRING_DATA_MONGODB_URI").expect("SPRING_DATA_MONGODB_URI must be set"); + let max_payload_size = env::var("MAX_PAYLOAD_SIZE").unwrap_or("10".to_string()).parse::().unwrap(); let aws_service = Arc::new( AWSService::new( @@ -54,6 +55,7 @@ async fn main() -> std::io::Result<()> { App::new() .wrap(cors) + .app_data(web::PayloadConfig::default().limit(max_payload_size * 1024 * 1024)) .app_data(web::Data::new(Arc::clone(&aws_service))) .app_data(web::Data::new(Arc::clone(&mongo_service))) .route("/get/{id}/content", web::get().to(get_content_handler)) From 34ca45a1b9a87fcdabe0815a63f7094214b19b1d Mon Sep 17 00:00:00 2001 From: Loudbook Date: Wed, 11 Dec 2024 21:22:41 -0500 Subject: [PATCH 184/188] MAX_PAYLOAD_SIZE --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index 1139491..b9430d3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,6 +25,7 @@ services: - DESCRIPTION=${DESCRIPTION} - DISABLE_NEW=${DISABLE_NEW} - FAVICON_URL=${FAVICON_URL} + - MAX_PAYLOAD_SIZE=${MAX_PAYLOAD_SIZE} depends_on: - backend networks: From e1e72cb8a0f34e2e9186e11fa823b232807629cd Mon Sep 17 00:00:00 2001 From: Loudbook Date: Wed, 11 Dec 2024 21:23:07 -0500 Subject: [PATCH 185/188] Update pastebook.conf --- pastebook.conf | 2 -- 1 file changed, 2 deletions(-) diff --git a/pastebook.conf b/pastebook.conf index cff6b05..e6db5c7 100644 --- a/pastebook.conf +++ b/pastebook.conf @@ -47,8 +47,6 @@ server { ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; - client_max_body_size 6M; - location / { proxy_buffering off; proxy_set_header X-Real-IP $remote_addr; From 2625d97d49785d9a75b02a88a7b7c93bbf7d5cae Mon Sep 17 00:00:00 2001 From: Loudbook Date: Wed, 11 Dec 2024 21:58:26 -0500 Subject: [PATCH 186/188] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index e9e5504..fb075d4 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ TITLE= DESCRIPTION= DISABLE_NEW= FAVICON_URL= +MAX_PAYLOAD_SIZE= ``` All of the following are optional. You can leave it all blank, or not even have a `.env` file at all. @@ -32,6 +33,8 @@ All of the following are optional. You can leave it all blank, or not even have `FAVICON_URL` - The URL that the favicon will be provided with. +`MAX_PAYLOAD_SIZE` - The maximum paste size in megabytes. + ### Creation Run the following. ```bash From 1e8c9e61d646aa60a6c6c8cca08c85f7d74dcdd8 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Thu, 12 Dec 2024 14:09:38 -0500 Subject: [PATCH 187/188] Improve logging --- backend/src/database/aws_service.rs | 5 +++-- backend/src/database/migration_service.rs | 21 +++++++++++---------- backend/src/database/mongodb_service.rs | 5 +++-- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/backend/src/database/aws_service.rs b/backend/src/database/aws_service.rs index 7a5073f..bca9f39 100644 --- a/backend/src/database/aws_service.rs +++ b/backend/src/database/aws_service.rs @@ -2,6 +2,7 @@ use anyhow::Result; use aws_sdk_s3::config::{Credentials, Region, SharedCredentialsProvider}; use aws_sdk_s3::primitives::ByteStream; use aws_sdk_s3::{Client, Config}; +use log::info; pub struct AWSService { client: Client, @@ -10,7 +11,7 @@ pub struct AWSService { impl AWSService { pub async fn new(endpoint: &str, bucket_name: &str, access_key: &str, secret_key: &str) -> Result { - println!("Connecting to AWS S3..."); + info!("Connecting to AWS S3..."); let region = Region::new("auto"); let credentials = Credentials::from_keys(access_key, secret_key, None); let shared_credentials = SharedCredentialsProvider::new(credentials); @@ -25,7 +26,7 @@ impl AWSService { let client = Client::from_conf(config); - println!("Connected to AWS S3."); + info!("Connected to AWS S3."); Ok(Self { client, diff --git a/backend/src/database/migration_service.rs b/backend/src/database/migration_service.rs index 65d404b..4a026ab 100644 --- a/backend/src/database/migration_service.rs +++ b/backend/src/database/migration_service.rs @@ -1,6 +1,7 @@ use crate::models::paste::Paste; use crate::models::user::User; use futures_util::StreamExt; +use log::{error, info}; use mongodb::bson::{doc, Document}; use mongodb::{Collection, Database}; @@ -22,17 +23,17 @@ impl MigrationService { } pub async fn run_migrations(&self) { - self.user_migration_12_11_24().await.map_err(|e| println!("Error migrating users: {}", e)).ok(); - self.paste_migration_12_11_24().await.map_err(|e| println!("Error migrating pastes: {}", e)).ok(); + self.user_migration_12_11_24().await.map_err(|e| error!("Error migrating users: {}", e)).ok(); + self.paste_migration_12_11_24().await.map_err(|e| error!("Error migrating pastes: {}", e)).ok(); } pub async fn user_migration_12_11_24(&self) -> Result<(), mongodb::error::Error> { if !self.database.list_collection_names().await?.contains(&"user".to_string()) { - println!("No users to migrate."); + info!("No users to migrate."); return Ok(()); } - println!("Migrating users..."); + info!("Migrating users..."); let old_user_collection = self.database.collection::("user"); let mut amount = 0; @@ -48,7 +49,7 @@ impl MigrationService { let last_visit = old_user.get_i64("lastVisit").unwrap_or_default(); if user_ip.is_empty() || user_id.is_empty() { - println!("Skipping user with empty IP or ID."); + info!("Skipping user with empty IP or ID."); continue; } @@ -65,7 +66,7 @@ impl MigrationService { amount += 1; } - println!("Migrated {} out of {} users", amount, target_amount); + info!("Migrated {} out of {} users", amount, target_amount); let qualified_old_database_name = self.database.name().to_owned() + ".user"; let qualified_new_database_name = self.database.name().to_owned() + ".user_migrated_12_11_24"; @@ -81,11 +82,11 @@ impl MigrationService { pub async fn paste_migration_12_11_24(&self) -> Result<(), mongodb::error::Error> { if !self.database.list_collection_names().await?.contains(&"pastePrivateDTO".to_string()) { - println!("No pastes to migrate."); + info!("No pastes to migrate."); return Ok(()); } - println!("Migrating pastes..."); + info!("Migrating pastes..."); let old_paste_collection = self.database.collection::("pastePrivateDTO"); let mut amount = 0; @@ -102,7 +103,7 @@ impl MigrationService { let paste_wrap = old_paste.get_bool("wrap").unwrap_or_default(); if paste_id.is_empty() { - println!("Skipping paste with empty ID."); + info!("Skipping paste with empty ID."); continue; } @@ -121,7 +122,7 @@ impl MigrationService { amount += 1; } - println!("Migrated {} out of {} pastes", amount, target_amount); + info!("Migrated {} out of {} pastes", amount, target_amount); let qualified_old_database_name = self.database.name().to_owned() + ".pastePrivateDTO"; let qualified_new_database_name = self.database.name().to_owned() + ".pastePrivateDTO_migrated_12_11_24"; diff --git a/backend/src/database/mongodb_service.rs b/backend/src/database/mongodb_service.rs index 771ec2c..7bb7222 100644 --- a/backend/src/database/mongodb_service.rs +++ b/backend/src/database/mongodb_service.rs @@ -1,3 +1,4 @@ +use log::info; use mongodb::bson::{doc, uuid}; use mongodb::{Client, Collection, Cursor}; use mongodb::options::ClientOptions; @@ -13,7 +14,7 @@ pub struct MongoService { impl MongoService { pub async fn new(uri: &str, db_name: &str) -> MongoResult { - println!("Connecting to MongoDB..."); + info!("Connecting to MongoDB..."); let client_options = ClientOptions::parse(uri).await?; let client = Client::with_options(client_options)?; @@ -22,7 +23,7 @@ impl MongoService { let user_collection = database.collection::("users"); let paste_collection = database.collection::("pastes"); - println!("Connected to MongoDB."); + info!("Connected to MongoDB."); let migration_service = MigrationService::new(&database, &admin_database, &user_collection, &paste_collection); migration_service.run_migrations().await; From 7affa01071347983a2a72dd5afb282c40371adbe Mon Sep 17 00:00:00 2001 From: Loudbook Date: Thu, 12 Dec 2024 16:48:18 -0500 Subject: [PATCH 188/188] Fix ID Key --- backend/src/database/mongodb_service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/database/mongodb_service.rs b/backend/src/database/mongodb_service.rs index 7bb7222..6493f61 100644 --- a/backend/src/database/mongodb_service.rs +++ b/backend/src/database/mongodb_service.rs @@ -39,7 +39,7 @@ impl MongoService { let update = doc! { "$inc": { "requests": 1 }, "$setOnInsert": { - "_id": uuid::Uuid::new().to_string(), + "id": uuid::Uuid::new().to_string(), "created_at": chrono::Utc::now().timestamp_millis(), "banned": false }